mirror of
https://github.com/status-im/sqlcipher.git
synced 2026-08-31 14:31:11 +00:00
track 3.7.2
This commit is contained in:
@@ -103,15 +103,15 @@ SHPREFIX =
|
||||
#
|
||||
#TCL_FLAGS =
|
||||
#TCL_FLAGS = -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.5linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
|
||||
|
||||
#### Linker options needed to link against the TCL library.
|
||||
#
|
||||
#LIBTCL = -ltcl -lm -ldl
|
||||
LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
|
||||
LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt
|
||||
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
|
||||
|
||||
#### Additional objects for SQLite library when TCL support is enabled.
|
||||
|
||||
+1
-1
@@ -748,7 +748,7 @@ tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DTCLSH=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
|
||||
$(LTCOMPILE) -DTCL_USE_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
$(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
|
||||
|
||||
tclsqlite3$(TEXE): tclsqlite-shell.lo libsqlite3.la
|
||||
$(LTLINK) -o $@ tclsqlite-shell.lo \
|
||||
|
||||
+4
-4
@@ -93,15 +93,15 @@ SHPREFIX = lib
|
||||
#
|
||||
#TCL_FLAGS =
|
||||
#TCL_FLAGS = -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.5linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
|
||||
|
||||
#### Linker options needed to link against the TCL library.
|
||||
#
|
||||
#LIBTCL = -ltcl -lm -ldl
|
||||
LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
|
||||
LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt
|
||||
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
|
||||
|
||||
#### Additional objects for SQLite library when TCL support is enabled.
|
||||
|
||||
+4
-4
@@ -110,15 +110,15 @@ SHPREFIX = lib
|
||||
#
|
||||
#TCL_FLAGS =
|
||||
#TCL_FLAGS = -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.4linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.4win -DSTATIC_BUILD=1
|
||||
TCL_FLAGS = -I/home/drh/tcltk/8.5linux
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1
|
||||
#TCL_FLAGS = -I/home/drh/tcltk/8.3hpux
|
||||
|
||||
#### Linker options needed to link against the TCL library.
|
||||
#
|
||||
#LIBTCL = -ltcl -lm -ldl
|
||||
LIBTCL = /home/drh/tcltk/8.4linux/libtcl8.4g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.4win/libtcl84s.a -lmsvcrt
|
||||
LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl
|
||||
#LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt
|
||||
#LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc
|
||||
|
||||
#### Additional objects for SQLite library when TCL support is enabled.
|
||||
|
||||
@@ -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.0.1.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.7.2.
|
||||
#
|
||||
# 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.0.1'
|
||||
PACKAGE_STRING='sqlite 3.7.0.1'
|
||||
PACKAGE_VERSION='3.7.2'
|
||||
PACKAGE_STRING='sqlite 3.7.2'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -1487,7 +1487,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.0.1 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.7.2 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1552,7 +1552,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.0.1:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.2:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1670,7 +1670,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.7.0.1
|
||||
sqlite configure 3.7.2
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1684,7 +1684,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.0.1, which was
|
||||
It was created by sqlite $as_me 3.7.2, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -12259,7 +12259,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
for ac_prog in tclsh8.4 tclsh
|
||||
for ac_prog in tclsh8.5 tclsh
|
||||
do
|
||||
# Extract the first word of "$ac_prog", so it can be a program name with args.
|
||||
set dummy $ac_prog; ac_word=$2
|
||||
@@ -13972,7 +13972,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.0.1, which was
|
||||
This file was extended by sqlite $as_me 3.7.2, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14025,7 +14025,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.0.1
|
||||
sqlite config.status 3.7.2
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ USE_AMALGAMATION=1
|
||||
# if not, then we fall back to plain tclsh.
|
||||
# TODO: try other versions before falling back?
|
||||
#
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.4 tclsh], none)
|
||||
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.5 tclsh], none)
|
||||
if test "$TCLSH_CMD" = "none"; then
|
||||
# If we can't find a local tclsh, then building the amalgamation will fail.
|
||||
# We act as though --disable-amalgamation has been used.
|
||||
|
||||
+1
-1
@@ -2653,7 +2653,7 @@ static void hashDestroy(void *p){
|
||||
** used to retrieve the respective implementations.
|
||||
**
|
||||
** Calling sqlite3Fts3SimpleTokenizerModule() sets the value pointed
|
||||
** to by the argument to point a the "simple" tokenizer implementation.
|
||||
** to by the argument to point to the "simple" tokenizer implementation.
|
||||
** Function ...PorterTokenizerModule() sets *pModule to point to the
|
||||
** porter tokenizer/stemmer implementation.
|
||||
*/
|
||||
|
||||
@@ -78,7 +78,6 @@ int sqlite3_fts3_enable_parentheses = 0;
|
||||
#define SQLITE_FTS3_DEFAULT_NEAR_PARAM 10
|
||||
|
||||
#include "fts3Int.h"
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -104,7 +103,7 @@ struct ParseContext {
|
||||
** negative values).
|
||||
*/
|
||||
static int fts3isspace(char c){
|
||||
return (c&0x80)==0 ? isspace(c) : 0;
|
||||
return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f';
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "fts3_tokenizer.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "fts3Int.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "fts3Int.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "fts3_tokenizer.h"
|
||||
|
||||
@@ -53,6 +52,9 @@ typedef struct simple_tokenizer_cursor {
|
||||
static int simpleDelim(simple_tokenizer *t, unsigned char c){
|
||||
return c<0x80 && t->delim[c];
|
||||
}
|
||||
static int fts3_isalnum(int x){
|
||||
return (x>='0' && x<='9') || (x>='A' && x<='Z') || (x>='a' && x<='z');
|
||||
}
|
||||
|
||||
/*
|
||||
** Create a new tokenizer instance.
|
||||
@@ -87,7 +89,7 @@ static int simpleCreate(
|
||||
/* Mark non-alphanumeric ASCII characters as delimiters */
|
||||
int i;
|
||||
for(i=1; i<0x80; i++){
|
||||
t->delim[i] = !isalnum(i) ? -1 : 0;
|
||||
t->delim[i] = !fts3_isalnum(i) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +195,7 @@ static int simpleNext(
|
||||
** case-insensitivity.
|
||||
*/
|
||||
unsigned char ch = p[iStartOffset+i];
|
||||
c->pToken[i] = (char)(ch<0x80 ? tolower(ch) : ch);
|
||||
c->pToken[i] = (char)((ch>='A' && ch<='Z') ? ch-'A'+'a' : ch);
|
||||
}
|
||||
*ppToken = c->pToken;
|
||||
*pnBytes = n;
|
||||
|
||||
+1
-2
@@ -139,7 +139,7 @@ SQLite. Documentation follows.
|
||||
3.2 The SQLITE_MAX_LIKE_PATTERN_LENGTH Macro
|
||||
|
||||
Passing very long patterns to the built-in SQLite LIKE operator can
|
||||
cause a stack overflow. To curb this problem, SQLite defines the
|
||||
cause excessive CPU usage. To curb this problem, SQLite defines the
|
||||
SQLITE_MAX_LIKE_PATTERN_LENGTH macro as the maximum length of a
|
||||
pattern in bytes (irrespective of encoding). The default value is
|
||||
defined in internal header file "limits.h".
|
||||
@@ -167,4 +167,3 @@ SQLite. Documentation follows.
|
||||
malicious users may execute arbitrary SQL (i.e. gears), they
|
||||
should be prevented from invoking the icu_load_collation() function,
|
||||
possibly using the authorisation callback.
|
||||
|
||||
|
||||
+2
-3
@@ -1072,11 +1072,10 @@ static int rtreeFilter(
|
||||
** idxNum idxStr Strategy
|
||||
** ------------------------------------------------
|
||||
** 1 Unused Direct lookup by rowid.
|
||||
** 2 See below R-tree query.
|
||||
** 3 Unused Full table scan.
|
||||
** 2 See below R-tree query or full-table scan.
|
||||
** ------------------------------------------------
|
||||
**
|
||||
** If strategy 1 or 3 is used, then idxStr is not meaningful. If strategy
|
||||
** If strategy 1 is used, then idxStr is not meaningful. If strategy
|
||||
** 2 is used, idxStr is formatted to contain 2 bytes for each
|
||||
** constraint used. The first two bytes of idxStr correspond to
|
||||
** the constraint in sqlite3_index_info.aConstraintUsage[] with
|
||||
|
||||
@@ -88,8 +88,8 @@ do_test rtree6.2.2 {
|
||||
do_test rtree6.2.3 {
|
||||
query_plan {SELECT * FROM t1,t2 WHERE k=ii}
|
||||
} [list \
|
||||
{TABLE t2} \
|
||||
{TABLE t1 VIRTUAL TABLE INDEX 1:} \
|
||||
{TABLE t1 VIRTUAL TABLE INDEX 2:} \
|
||||
{TABLE t2 USING PRIMARY KEY} \
|
||||
]
|
||||
|
||||
do_test rtree6.2.4 {
|
||||
@@ -102,8 +102,8 @@ do_test rtree6.2.4 {
|
||||
do_test rtree6.2.5 {
|
||||
query_plan {SELECT * FROM t1,t2 WHERE k=ii AND x1<v}
|
||||
} [list \
|
||||
{TABLE t2} \
|
||||
{TABLE t1 VIRTUAL TABLE INDEX 1:} \
|
||||
{TABLE t1 VIRTUAL TABLE INDEX 2:} \
|
||||
{TABLE t2 USING PRIMARY KEY} \
|
||||
]
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Backport\sfix\s[a6bb2108bfb56]\sfor\sa\stypo\sin\sthe\sOS/2\sinterface.
|
||||
D 2010-08-04T12:31:11
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
F Makefile.vxworks 4314cde20a1d9460ec5083526ea975442306ae7e
|
||||
C Version\s3.7.2\srelease\scandidate\s1
|
||||
D 2010-08-23T18:52:01
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 84a3e1c74ef99b2c08ceb1142780ac63d6e44c3d
|
||||
F VERSION 6062e0026a5ab33dabb4efae38604d40115819ec
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
|
||||
@@ -24,8 +24,8 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 37e90c7b9b88007f064f690ed79e64e228a51158 x
|
||||
F configure.ac 14740970ddb674d92a9f5da89083dff1179014ff
|
||||
F configure a5dab32df872ed3fe248c7f0cbc324595c169781 x
|
||||
F configure.ac 699040cc9abb7465dca5a2972bc89d227fd8f734
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
|
||||
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
|
||||
@@ -63,32 +63,32 @@ 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 9dec342fa1cf0914da679a3b7c0d4b53a27883ba
|
||||
F ext/fts3/fts3.c e818310c473d7703f7818887a3537ec42ae0d528
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 70528ba8c33991699f96ecc64112122833cdbdb5
|
||||
F ext/fts3/fts3_expr.c f4ff02ebe854e97ac03ff00b38b728a9ab57fd4b
|
||||
F ext/fts3/fts3_expr.c 42d5697731cd30fbeabd081bb3e6d3df5531f606
|
||||
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 7546e4503e286a67fd4f2a82159620e3e9c7a1bc
|
||||
F ext/fts3/fts3_snippet.c bc582c38e194b48818da862f9e6f293cc44e29ee
|
||||
F ext/fts3/fts3_tokenizer.c 1a49ee3d79cbf0b9386250370d9cbfe4bb89c8ff
|
||||
F ext/fts3/fts3_porter.c 8df6f6efcc4e9e31f8bf73a4007c2e9abca1dfba
|
||||
F ext/fts3/fts3_snippet.c 2c4c921155e4b6befd272041fb903d999ac07d30
|
||||
F ext/fts3/fts3_tokenizer.c b4f2d01c24573852755bc92864816785dae39318
|
||||
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
|
||||
F ext/fts3/fts3_tokenizer1.c b6d86d1d750787db5c168c73da4e87670ed890a1
|
||||
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
|
||||
F ext/fts3/fts3_write.c 4b21a0c6f2772b261f14e3a2e80e1e3e849268b0
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
|
||||
F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c c7a18311f2d6ae9a42838e9c04b9e670483b4feb
|
||||
F ext/rtree/rtree.c f2fbb6470155316027a8b888e8623bc1819fe443
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 51bb0cd0405970501e63258401ae5ad235a4f468
|
||||
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
|
||||
F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
|
||||
F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
|
||||
F ext/rtree/rtree5.test 92508f5152a50110af6551fa5b769d1bbd7c4ef3
|
||||
F ext/rtree/rtree6.test 11aade5311789068ca659be24a47cc0d852b1971
|
||||
F ext/rtree/rtree6.test 903720aaab819764c3693aaac0affe8174104ac8
|
||||
F ext/rtree/rtree7.test 6fd29fb8e13795c822f4ceeea92ab5d61c96976d
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
@@ -109,40 +109,40 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c a9ff6f14b3935502537e90194b66c7bc79bed317
|
||||
F src/analyze.c 3457a2af126eb78f20ad239c225a2c8ed61b78b6
|
||||
F src/alter.c 8dc27638e7e2553e80b2b621f232be5eb1e85ef3
|
||||
F src/analyze.c da65ce99bb159b10e85a1e460adbe53a88062500
|
||||
F src/attach.c 17bec1f18254d9341369f20f90ba24ce35d20d10
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 51d83300fe0baee39405c416ceb19a58ed30a8ed
|
||||
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
|
||||
F src/backup.c 8ff0b7018df253c7f30d3f9702b0b16f19209d5c
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 0de928e4da0fb4ef15e33bf3ff13656d0bc98e73
|
||||
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
|
||||
F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291
|
||||
F src/build.c 559d38b48f79bc92370c082f4606eefe1e8f94ac
|
||||
F src/callback.c 01843bdf4b0420fd28046525d150fcd9802931a9
|
||||
F src/btree.c 5047fb303cdf6806a42676a6f513c57e15b7d69b
|
||||
F src/btree.h b4ba2fdf6b64c7c376bdfffa826af6b786b151d9
|
||||
F src/btreeInt.h 5b034ff54800046cc5870605d683ac1f9134bd99
|
||||
F src/build.c 0018d49629fc4807100c988dd191dd95e185bb38
|
||||
F src/callback.c da3c38d0ef5d7f04fae371e519bda61aa9cb1704
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
|
||||
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
|
||||
F src/delete.c 41cb4f78557810eecc167b7e2317de7e12d20929
|
||||
F src/expr.c 96bda574284ead53ba7af6334414b4e958cc866a
|
||||
F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
|
||||
F src/expr.c 9ee507c3dc6eaa5657cbd1dad026cdeda89c559f
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
|
||||
F src/func.c 0c28599430856631216b6c0131c51c89bf516026
|
||||
F src/fkey.c 58bbf52c6ddd3f64ca40a3230f9e548a83a5cb16
|
||||
F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d9476f23f85a20eea3cc25a4b9f9cbae77a33bf2
|
||||
F src/insert.c a4995747c062256582a90b4f87f716e11b067050
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
|
||||
F src/main.c a487fe90aecaccb142e4a6b738c7e26e99145bcd
|
||||
F src/malloc.c 09c3777bf733a387bec6aa344e455eb4e8ecf47e
|
||||
F src/loadext.c 6d422ea91cf3d2d00408c5a8f2391cd458da85f8
|
||||
F src/main.c 99622181f36d68e9f2a851c7b34263b3dcd03470
|
||||
F src/malloc.c 19a468460c7df72de245f10c06bd0625777b7c83
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
|
||||
F src/mem2.c 2ee7bdacda8299b5a91cff9f7ee3e46573195c38
|
||||
F src/mem2.c 9e5f72e38573db9598fe60d3fa530d473cc8714e
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c eb7a5cb98915dd7a086fa415ce3a5a0f20d0acff
|
||||
F src/memjournal.c 4a93a25ad9f76c40afa070ffd7187eb3a5fd7aee
|
||||
@@ -150,90 +150,90 @@ F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
|
||||
F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
|
||||
F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151
|
||||
F src/mutex_os2.c 6a62583e374ba3ac1a3fcc0da2bfdac7d3942689
|
||||
F src/mutex_unix.c cf84466b4fdd2baa0d5a10bb19f08b2abc1ce42e
|
||||
F src/mutex_w32.c 1fe0e735897be20e09dd6f53c3fb516c6b48c0eb
|
||||
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
|
||||
F src/mutex_unix.c abb8c98a6c27c57280e71522d059e929c708d019
|
||||
F src/mutex_w32.c b7ed3366a1d44a62a17d4eaefdaa2e7c25f944c2
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 60178f518c4d6c0dcb59f7292232281d7bea2dcf
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
|
||||
F src/os_unix.c 3109e0e5a0d5551bab2e8c7322b20a3b8b171248
|
||||
F src/os_win.c 1f8b0a1a5bcf6289e7754d0d3c16cec16d4c93ab
|
||||
F src/pager.c 78ca1e1f3315c8227431c403c04d791dccf242fb
|
||||
F src/pager.h 879fdde5a102d2f21a3135d6f647530b21c2796c
|
||||
F src/parse.y 220a11ac72e2c9dffbf4cbe5fe462f328bd8d884
|
||||
F src/os_unix.c 11194cbcf6a57456e58022dc537ab8c3497d9bb9
|
||||
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
|
||||
F src/pager.c a5f5d9787b11dfb0b6082e6f5846d00b459a8e19
|
||||
F src/pager.h ef8c8f71ab022cc2fff768a1175dd32355be9dcd
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c 3a7c28f46a61b43ff0b5c087a7983c154f4b264c
|
||||
F src/pragma.c 4a79269ea6f86150fb8e44688c753989fc7238dd
|
||||
F src/prepare.c f045aeff869d6409a2eae2fe08f7dc2df9528195
|
||||
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
|
||||
F src/pcache1.c e921e8a1d52c93abde63cb6dad1fa39770410c52
|
||||
F src/pragma.c 8b24ce00a93de345b6c3bd1e1e2cfba9f63d2325
|
||||
F src/prepare.c ce4c35a2b1d5fe916e4a46b70d24a6e997d7c4c6
|
||||
F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c 4903ff1bbd08b55cbce00ea43c645530de41b362
|
||||
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
||||
F src/sqlite.h.in 8b05aef506d9bc7fc7da1572744e3174cb16ed59
|
||||
F src/select.c 8add6cab889fc02e1492eda8dba462ccf11f51dd
|
||||
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
|
||||
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h d9e42f2029d4c526f9ba960bda1980ef17429c30
|
||||
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
|
||||
F src/status.c 4df6fe7dce2d256130b905847c6c60055882bdbe
|
||||
F src/sqliteInt.h e33b15e8176442bf7484f0e716edfd1ce03b2979
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c ae1e4fb653c91ddad7e2534d209711a12604ccc4
|
||||
F src/test1.c ff3b4533fc4d78d1bff2ef831a5791db55096ed3
|
||||
F src/test2.c e3f564ab1e9fd0b47b0c9e23e7054e38bf0836cf
|
||||
F src/tclsqlite.c cacee9482417b6fc6043f6bb831ff9496d46242d
|
||||
F src/test1.c 55005c9781b157b1d215ba145768783b9abae78c
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
|
||||
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
|
||||
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
|
||||
F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
|
||||
F src/test5.c e1a19845625144caf038031234a12185e40d315c
|
||||
F src/test6.c c7256cc21d2409486d094277d5b017e8eced44ba
|
||||
F src/test7.c 3f2d63e4ccf97f8c2cf1a7fa0a3c8e2e2a354e6e
|
||||
F src/test8.c f959db9a22d882013b64c92753fa793b2ce3bdea
|
||||
F src/test7.c d67f65d82815eb0b57699b122ca0145dbea55bbb
|
||||
F src/test8.c 6b1d12912a04fe6fca8c45bb9c3ea022f4352228
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
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 5a11c51af2156e2d07186930b36f2b8239a4393f
|
||||
F src/test_demovfs.c da81a5f7785bb352bda7911c332a983ec4f17f27
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
|
||||
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
|
||||
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
|
||||
F src/test_journal.c 424a334cdfdc8a6f975abe3641440147bded3185
|
||||
F src/test_journal.c 785edd54f963aefb3c1628124170a56697c68c70
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 4ab85f2b8ae3a237f4e6557b0a641181a19ffab1
|
||||
F src/test_malloc.c 09a88f0c111201dc4f8c20470aa1b5f611d59200
|
||||
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
|
||||
F src/test_onefile.c 40cf9e212a377a6511469384a64b01e6e34b2eec
|
||||
F src/test_osinst.c f408c6a181f2fb04c56273afd5c3e1e82f60392c
|
||||
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c 6ebaf2a86d01ccda24e49c148f1d33e8badda06e
|
||||
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 7e291f85256516ebde6633bc381ff7eedfa30234
|
||||
F src/test_vfs.c 702e52636113f6b9721da90ef1bf26e07fff414d
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 67e95c76d625b92d43409ace771c8e0d02a09ac2
|
||||
F src/update.c 19c899c23cd29fd102c9068e0b0ff5b087204beb
|
||||
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
|
||||
F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
|
||||
F src/update.c 1521162d20c2994af1fdc8833e1a88dae09052c8
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
|
||||
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
|
||||
F src/vdbe.c 6294de3327e09d14e9c06ecfd10e57c2d8e85307
|
||||
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
|
||||
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
|
||||
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
|
||||
F src/vdbeaux.c 7f99c1f00e4b31e8b28d8a87ecc2322bb46ae99c
|
||||
F src/vdbe.c 66c262a923915e596379b1d597178e04c5d719e4
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h ffd68c4d4229227a5089bec53a1c635146177abc
|
||||
F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
|
||||
F src/vdbeaux.c c73bcefcebfd3d2cf91bf6a41ef0fb0d884814c6
|
||||
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
|
||||
F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807
|
||||
F src/vdbemem.c e5673f81a2381b35c60e73ef0a8502be2ab1041e
|
||||
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
|
||||
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
|
||||
F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82
|
||||
F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2
|
||||
F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4
|
||||
F src/wal.c 5ac2119e23ee4424599d4275b66dc88d612a0543
|
||||
F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 903a7828a0a7de03b5d0f1b5eff222d8d5b138f1
|
||||
F src/where.c 7db3e41c2a846f9deeb24f1bbb75461b4010b7b5
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce
|
||||
@@ -244,7 +244,7 @@ F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test bf692e7db414f268a136bade16c03a1bdbb9240c
|
||||
F test/analyze2.test 59dac6c399c0c5d1a90a11ee7cc606743fb6db93
|
||||
F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8
|
||||
F test/analyze3.test 6d4f4b0929545a9d1af803a0608a0c51b92a3537
|
||||
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
@@ -262,6 +262,7 @@ F test/autoindex1.test 7df441bf0e7a88644eb80993339dbf1db3a12c68
|
||||
F test/autovacuum.test bb7c0885e6f8f1d633045de48f2b66082162766d
|
||||
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test 49bd844eb245f0b2b6f2a3f8bebad0065403a9a7
|
||||
F test/backup.test 200e64bd91244b73ca8094bc1e03dfc83cc94c2e
|
||||
F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
@@ -304,7 +305,7 @@ F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
|
||||
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/colmeta.test 087c42997754b8c648819832241daf724f813322
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 0ed68b11f22721052d880ee80bd528a0e0828236
|
||||
F test/conflict.test f2f2b2950730a9532e11e468070cebf389f5c375
|
||||
F test/corrupt.test 1a5bef8b2d178859af69814ecedcd37219a89968
|
||||
F test/corrupt2.test 808a28d0ca3b97e9aa8c91cd2b485ea2700b76d1
|
||||
F test/corrupt3.test a399dacccb91c732f6b071c913e70d195af8c058
|
||||
@@ -333,7 +334,7 @@ F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/date.test 6354b883f922c38046a8efbad187cc95df6da023
|
||||
F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e
|
||||
F test/dbstatus.test 946e1399d4574fc5dac934cceedbc76924af3f5a
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
@@ -343,21 +344,22 @@ F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
|
||||
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_expr.test 141e53fea525bce4f5403fcb0067b88e64fec5eb
|
||||
F test/e_expr.test 8a35ce2718c61e871970bda09f4f3e549067c1ba
|
||||
F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
|
||||
F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
|
||||
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test 5fe18e10a159342dd52ca14b1554e33f98734267
|
||||
F test/exclusive.test b1f9012cabc124af947165d15ffa62ad20f63db8
|
||||
F test/exclusive2.test fcbb1c9ca9739292a0a22a3763243ad6d868086b
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
|
||||
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test f77c92141960b7933bc6691631d2ad62257ef40a
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test 098c06c139a79f690301a43511cd1f6420ae5433
|
||||
F test/fkey2.test e028cd80aa0bd38541c99214e3ba2dfccadffe6f
|
||||
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
|
||||
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
@@ -434,7 +436,7 @@ F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
|
||||
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
|
||||
F test/icu.test 1fc0ff9a3bafc80abf679b11afc0f8a3ce995abd
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test d49419c6df515852f477fa513f3317181d46bc92
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
@@ -448,7 +450,7 @@ F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291
|
||||
F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/indexedby.test 946ca2628a521f4ced0520421a0788345abaf3dc
|
||||
F test/indexedby.test 5a1180602f2e72c481467bd4cae05dae5dc36f47
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
|
||||
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
|
||||
@@ -463,7 +465,7 @@ F test/ioerr.test 390785ec65f10aa58a82b048ee12e9052d783fa8
|
||||
F test/ioerr2.test 1b56cb80d5b0726ee3ba325ca175734541e32955
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test fc6eddfec2efc2f1ed217b9eae4c1c1d3516ce86
|
||||
F test/ioerr5.test 89f69b09a6b5d4f5bbfe58d4231f28236d842dcb
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
@@ -473,13 +475,13 @@ F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/journal2.test 50a3604768494d4a337f194f0a9480e7c57dcb72
|
||||
F test/journal3.test ff175219be1b02d2f7e54297ad7e491b7533edb6
|
||||
F test/jrnlmode.test 2d5a8b6d68de8512f522532731d90ca96912f3b7
|
||||
F test/jrnlmode.test e3fe6c4a2c3213d285650dc8e33aab7eaaa5ce53
|
||||
F test/jrnlmode2.test a19e28de1a6ec898067e46a122f1b71c9323bf00
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 4b594af9eddfd01018df1e9b1d18721aff619fa7
|
||||
F test/like.test 565d240313f15a8afa8d7098dc9fe303c1e2a496
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
|
||||
F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0
|
||||
@@ -491,7 +493,7 @@ F test/lock4.test c82268c031d39345d05efa672f80b025481b3ae5
|
||||
F test/lock5.test b2abb5e711bc59b0eae00f6c97a36ec9f458fada
|
||||
F test/lock6.test 8df56060f396151777390982422c800d026e1722
|
||||
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
|
||||
F test/lock_common.tcl e7013c6208f5fa818735c324eb0249b4c0f317cf
|
||||
F test/lock_common.tcl 18c637fc89e12f1ac0d27d2186f12c3d3f789e3e
|
||||
F test/lookaside.test 382e7bc2fab23d902c8eafb1b9ed7ababfff75a6
|
||||
F test/main.test 9d7bbfcc1b52c88ba7b2ba6554068ecf9939f252
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
@@ -537,19 +539,20 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test a44e04df1486fcfb02d32468cbcd3c8e1e433723
|
||||
F test/notify1.test 8433bc74bd952fb8a6e3f8d7a4c2b28dfd69e310
|
||||
F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
|
||||
F test/notify3.test 7eeba3628c4e707c004b72a2489c48fbdbc5c2ee
|
||||
F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/pager1.test d8e4b2bc8164c920e6ea0572c9e13576d6e4f3fa
|
||||
F test/pager2.test f5c757c271ce642d36a393ecbfb3aef1c240dcef
|
||||
F test/pagerfault.test c1d176326ce244db157ce9c3ba128be2a9b172d6
|
||||
F test/pager1.test 6922029d71a8090169c71a67a141b6b94ad17d50
|
||||
F test/pager2.test 0fbb6b6dc40ce1fecfe758c555a748ad2e9beaa3
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pagerfault.test 84c6a4fcfe1a9e450fc1cec86f5baebfb017e53e
|
||||
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
|
||||
F test/pageropt.test 8146bf448cf09e87bb1867c2217b921fb5857806
|
||||
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
|
||||
F test/pcache.test 4118a183908ecaed343a06fcef3ba82e87e0129d
|
||||
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
|
||||
F test/permutations.test 3fe47c21c32b294b2354e702a25bfbff65747bb1
|
||||
F test/permutations.test 17498d1219f922d5a6da893a94c4dc7766fb2426
|
||||
F test/pragma.test ed78d200f65c6998df51196cb8c39d5300570f24
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
@@ -586,9 +589,9 @@ F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
|
||||
F test/selectC.test 33bb5673a8141df193c6fd56e6de7fea38b8d2ee
|
||||
F test/selectC.test f9bf1bc4581b5b8158caa6e4e4f682acb379fb25
|
||||
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
|
||||
F test/shared.test 3b448dc0f7a9356e641894ed81c27599f39d809d
|
||||
F test/shared.test b9114eaea7e748a3a4c8ff7b9ca806c8f95cef3e
|
||||
F test/shared2.test d6ba4ca1827ea36a1ac23a99e3c36eeac9165450
|
||||
F test/shared3.test d69bdd5f156580876c5345652d21dc2092e85962
|
||||
F test/shared4.test d0fadacb50bb6981b2fb9dc6d1da30fa1edddf83
|
||||
@@ -622,7 +625,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
|
||||
F test/tempdb.test 800c36623d67a2ad1f58784b9c5644e0405af6e6
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
|
||||
F test/tester.tcl 295800403a36c4319354482749e9282ce47b7edc
|
||||
F test/tester.tcl 6135019fcfac363ea0e11aee670cc97080ab578e
|
||||
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
|
||||
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
|
||||
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
|
||||
@@ -633,12 +636,14 @@ F test/thread2.test e08034b83fe9693ade77049732518e5b3d2d700d
|
||||
F test/thread_common.tcl 2aa6f2fdcd4d6e461169c3e5ca098eebf643b863
|
||||
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
|
||||
F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
|
||||
F test/threadtest3.c 58df1e3c060f534fd7fb0702331b0acc41c381d8
|
||||
F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab
|
||||
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
|
||||
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
|
||||
F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
|
||||
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
|
||||
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
|
||||
F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
|
||||
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
@@ -647,6 +652,7 @@ F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
|
||||
F test/tkt-d11f09d36e.test fb44f7961aa6d4b632fb7b9768239832210b5fc7
|
||||
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
|
||||
F test/tkt-f3e5abed55.test 91713833e266fbdc60f2030e05647ad4762073f6
|
||||
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
|
||||
F test/tkt-f973c7ac31.test 1da0ed15ec2c7749fb5ce2828cd69d07153ad9f4
|
||||
F test/tkt-fc62af4523.test 72825d3febdedcd5593a27989fc05accdbfc2bb4
|
||||
@@ -749,7 +755,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test cac41fe31adc1abb9fa08532762fc2b4f662ab03
|
||||
F test/triggerC.test 2a23edcc00684d084902ba5ec93e721775c3a70a
|
||||
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
|
||||
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
@@ -781,9 +787,9 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
|
||||
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
|
||||
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
|
||||
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
|
||||
F test/wal.test 1891e6f72dd437a1c2a48091aa9182ba17a8f780
|
||||
F test/wal2.test fa6dc4457b46988f46cf6c68ea51ebe341765f4a
|
||||
F test/wal3.test d2ae7e66f973bd6b58ce49e546b2c00f44fe0485
|
||||
F test/wal.test 70227190e713b3e7eb2a7d5ec3510b66db01f327
|
||||
F test/wal2.test 223f3e14d475730af772a7f5862d4bcfa7565c3a
|
||||
F test/wal3.test 695ea0f6c516423c611891df9a285aacd33344e3
|
||||
F test/wal4.test 3404b048fa5e10605facaf70384e6d2943412e30
|
||||
F test/wal_common.tcl 895d76138043b86bdccf36494054bdabcf65837b
|
||||
F test/walbak.test 4df1c7369da0301caeb9a48fa45997fd592380e4
|
||||
@@ -793,12 +799,13 @@ F test/walcrash.test e763841551d6b23677ccb419797c1589dcbdbaf5
|
||||
F test/walcrash2.test 019d60b89d96c1937adb2b30b850ac7e86e5a142
|
||||
F test/walfault.test 05c470688d742688e455dd56816bd6bcffa298f8
|
||||
F test/walhook.test ed00a40ba7255da22d6b66433ab61fab16a63483
|
||||
F test/walmode.test 5dc3008ef71988ecdd949ea16e5750e325b92b54
|
||||
F test/walmode.test 4ecd37284f245247f7935896ab66f6943f0432a0
|
||||
F test/walshared.test 985b4a3406b2b2dace1d52a42d26a11dd6900981
|
||||
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
|
||||
F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
|
||||
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where3.test aa44a9b29e8c9f3d7bb94a3bb3a95b31627d520d
|
||||
F test/where3.test 3bf8006d441b66a57bee02bb420423f84eb8fde3
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
@@ -825,10 +832,12 @@ 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 a738c71bc08ea9162baee9a14b3cf9994f181921
|
||||
F tool/shell1.test 930444cadb71ce9ce78bc6cd14ec21e6b69776ea
|
||||
F tool/shell2.test 5dc76b8005b465f420fed8241621da7513060ff3
|
||||
F tool/shell3.test 4fad469e8003938426355afdf34155f08c587836
|
||||
F tool/showdb.c 01c20e8181941b714fe07f72c64a7560fee17ff9
|
||||
F tool/shell4.test 35f9c3d452b4e76d5013c63e1fd07478a62f14ce
|
||||
F tool/shell5.test 62bfaf9267296da1b91e4b1c03e44e7b393f6a94
|
||||
F tool/showdb.c c7a978cf525ef0f8bc2fd29cd52108dd1dfa605a
|
||||
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
|
||||
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
@@ -840,14 +849,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 5074b85967df8f55739ba790924347c764288a88
|
||||
R f5778ea9917b1adb206cc22be6e49c29
|
||||
P 21a1e5961bba148fda50cc0b7d472ca74f90808a
|
||||
R aa9cc30f9dbcb7ea427137065cf4e4be
|
||||
U drh
|
||||
Z 60fae2989ec1bf91141b6299767f6365
|
||||
Z e73ee740c6593b4458c2d23b6fa7b923
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFMWV2SoxKgR168RlERAiENAJ9TfAN62Ul3mO+iNQD+b8HJNbjgOwCeIZwB
|
||||
BZSXOygjVggzK2g+JjZSHP8=
|
||||
=3zag
|
||||
iD8DBQFMcsNUoxKgR168RlERApyRAKCOHvk0Gn1uE2F8YVm3k/w13/3UugCeOh16
|
||||
bApiXjM1a7FP+Qr1HX5kWTQ=
|
||||
=L2Lf
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
042a1abb030a0711386add7eb6e10832cc8b0f57
|
||||
42537b60566f288167f1b5864a5435986838e3a3
|
||||
|
||||
@@ -769,7 +769,6 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
if( !pNew ) goto exit_begin_add_column;
|
||||
pParse->pNewTable = pNew;
|
||||
pNew->nRef = 1;
|
||||
pNew->dbMem = pTab->dbMem;
|
||||
pNew->nCol = pTab->nCol;
|
||||
assert( pNew->nCol>0 );
|
||||
nAlloc = (((pNew->nCol-1)/8)*8)+8;
|
||||
|
||||
+10
-13
@@ -490,21 +490,20 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
** If the Index.aSample variable is not NULL, delete the aSample[] array
|
||||
** and its contents.
|
||||
*/
|
||||
void sqlite3DeleteIndexSamples(Index *pIdx){
|
||||
void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
||||
#ifdef SQLITE_ENABLE_STAT2
|
||||
if( pIdx->aSample ){
|
||||
int j;
|
||||
sqlite3 *dbMem = pIdx->pTable->dbMem;
|
||||
for(j=0; j<SQLITE_INDEX_SAMPLES; j++){
|
||||
IndexSample *p = &pIdx->aSample[j];
|
||||
if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){
|
||||
sqlite3DbFree(pIdx->pTable->dbMem, p->u.z);
|
||||
sqlite3DbFree(db, p->u.z);
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(dbMem, pIdx->aSample);
|
||||
pIdx->aSample = 0;
|
||||
sqlite3DbFree(db, pIdx->aSample);
|
||||
}
|
||||
#else
|
||||
UNUSED_PARAMETER(db);
|
||||
UNUSED_PARAMETER(pIdx);
|
||||
#endif
|
||||
}
|
||||
@@ -543,7 +542,8 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
sqlite3DefaultRowEst(pIdx);
|
||||
sqlite3DeleteIndexSamples(pIdx);
|
||||
sqlite3DeleteIndexSamples(db, pIdx);
|
||||
pIdx->aSample = 0;
|
||||
}
|
||||
|
||||
/* Check to make sure the sqlite_stat1 table exists */
|
||||
@@ -587,18 +587,17 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase);
|
||||
if( pIdx ){
|
||||
int iSample = sqlite3_column_int(pStmt, 1);
|
||||
sqlite3 *dbMem = pIdx->pTable->dbMem;
|
||||
assert( dbMem==db || dbMem==0 );
|
||||
if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){
|
||||
int eType = sqlite3_column_type(pStmt, 2);
|
||||
|
||||
if( pIdx->aSample==0 ){
|
||||
static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES;
|
||||
pIdx->aSample = (IndexSample *)sqlite3DbMallocZero(dbMem, sz);
|
||||
pIdx->aSample = (IndexSample *)sqlite3DbMallocRaw(0, sz);
|
||||
if( pIdx->aSample==0 ){
|
||||
db->mallocFailed = 1;
|
||||
break;
|
||||
}
|
||||
memset(pIdx->aSample, 0, sz);
|
||||
}
|
||||
|
||||
assert( pIdx->aSample );
|
||||
@@ -621,10 +620,8 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
||||
if( n < 1){
|
||||
pSample->u.z = 0;
|
||||
}else{
|
||||
pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
|
||||
if( pSample->u.z ){
|
||||
memcpy(pSample->u.z, z, n);
|
||||
}else{
|
||||
pSample->u.z = sqlite3DbStrNDup(0, z, n);
|
||||
if( pSample->u.z==0 ){
|
||||
db->mallocFailed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -221,6 +221,15 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
/* Backup is not possible if the page size of the destination is changing
|
||||
** a a codec is in use.
|
||||
*/
|
||||
if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
|
||||
rc = SQLITE_READONLY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This loop runs once for each destination page spanned by the source
|
||||
** page. For each iteration, variable iOff is set to the byte offset
|
||||
** of the destination page.
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@
|
||||
#include "sqliteInt.h"
|
||||
|
||||
/* Size of the Bitvec structure in bytes. */
|
||||
#define BITVEC_SZ (sizeof(void*)*128) /* 512 on 32bit. 1024 on 64bit */
|
||||
#define BITVEC_SZ 512
|
||||
|
||||
/* Round the union size down to the nearest pointer boundary, since that's how
|
||||
** it will be aligned within the Bitvec struct. */
|
||||
|
||||
+99
-54
@@ -32,7 +32,16 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
||||
# define TRACE(X)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Extract a 2-byte big-endian integer from an array of unsigned bytes.
|
||||
** But if the value is zero, make it 65536.
|
||||
**
|
||||
** This routine is used to extract the "offset to cell content area" value
|
||||
** from the header of a btree page. If the page size is 65536 and the page
|
||||
** is empty, the offset should be 65536, but the 2-byte value stores zero.
|
||||
** This routine makes the necessary adjustment to 65536.
|
||||
*/
|
||||
#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
/*
|
||||
@@ -721,11 +730,16 @@ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
|
||||
** Given a page number of a regular database page, return the page
|
||||
** number for the pointer-map page that contains the entry for the
|
||||
** input page number.
|
||||
**
|
||||
** Return 0 (not a valid page) for pgno==1 since there is
|
||||
** no pointer map associated with page 1. The integrity_check logic
|
||||
** requires that ptrmapPageno(*,1)!=1.
|
||||
*/
|
||||
static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
|
||||
int nPagesPerMapPage;
|
||||
Pgno iPtrMap, ret;
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
if( pgno<2 ) return 0;
|
||||
nPagesPerMapPage = (pBt->usableSize/5)+1;
|
||||
iPtrMap = (pgno-2)/nPagesPerMapPage;
|
||||
ret = (iPtrMap*nPagesPerMapPage) + 2;
|
||||
@@ -1154,7 +1168,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
nFrag = data[hdr+7];
|
||||
assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf );
|
||||
gap = pPage->cellOffset + 2*pPage->nCell;
|
||||
top = get2byte(&data[hdr+5]);
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
if( gap>top ) return SQLITE_CORRUPT_BKPT;
|
||||
testcase( gap+2==top );
|
||||
testcase( gap+1==top );
|
||||
@@ -1164,7 +1178,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
/* Always defragment highly fragmented pages */
|
||||
rc = defragmentPage(pPage);
|
||||
if( rc ) return rc;
|
||||
top = get2byte(&data[hdr+5]);
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
}else if( gap+2<=top ){
|
||||
/* Search the freelist looking for a free slot big enough to satisfy
|
||||
** the request. The allocation is made from the first free slot in
|
||||
@@ -1206,7 +1220,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
if( gap+2+nByte>top ){
|
||||
rc = defragmentPage(pPage);
|
||||
if( rc ) return rc;
|
||||
top = get2byte(&data[hdr+5]);
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
assert( gap+nByte<=top );
|
||||
}
|
||||
|
||||
@@ -1372,10 +1386,10 @@ static int btreeInitPage(MemPage *pPage){
|
||||
u8 hdr; /* Offset to beginning of page header */
|
||||
u8 *data; /* Equal to pPage->aData */
|
||||
BtShared *pBt; /* The main btree structure */
|
||||
u16 usableSize; /* Amount of usable space on each page */
|
||||
int usableSize; /* Amount of usable space on each page */
|
||||
u16 cellOffset; /* Offset from start of page to first cell pointer */
|
||||
u16 nFree; /* Number of unused bytes on the page */
|
||||
u16 top; /* First byte of the cell content area */
|
||||
int nFree; /* Number of unused bytes on the page */
|
||||
int top; /* First byte of the cell content area */
|
||||
int iCellFirst; /* First allowable cell or freeblock offset */
|
||||
int iCellLast; /* Last possible cell or freeblock offset */
|
||||
|
||||
@@ -1384,12 +1398,12 @@ static int btreeInitPage(MemPage *pPage){
|
||||
hdr = pPage->hdrOffset;
|
||||
data = pPage->aData;
|
||||
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
|
||||
pPage->maskPage = pBt->pageSize - 1;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
pPage->nOverflow = 0;
|
||||
usableSize = pBt->usableSize;
|
||||
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
|
||||
top = get2byte(&data[hdr+5]);
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
/* To many cells for a single page. The page must be corrupt */
|
||||
@@ -1488,13 +1502,13 @@ static void zeroPage(MemPage *pPage, int flags){
|
||||
memset(&data[hdr+1], 0, 4);
|
||||
data[hdr+7] = 0;
|
||||
put2byte(&data[hdr+5], pBt->usableSize);
|
||||
pPage->nFree = pBt->usableSize - first;
|
||||
pPage->nFree = (u16)(pBt->usableSize - first);
|
||||
decodeFlags(pPage, flags);
|
||||
pPage->hdrOffset = hdr;
|
||||
pPage->cellOffset = first;
|
||||
pPage->nOverflow = 0;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );
|
||||
pPage->maskPage = pBt->pageSize - 1;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
pPage->nCell = 0;
|
||||
pPage->isInit = 1;
|
||||
}
|
||||
@@ -1802,7 +1816,7 @@ int sqlite3BtreeOpen(
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
pBt->secureDelete = 1;
|
||||
#endif
|
||||
pBt->pageSize = get2byte(&zDbHeader[16]);
|
||||
pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
|
||||
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
|
||||
pBt->pageSize = 0;
|
||||
@@ -2004,7 +2018,7 @@ int sqlite3BtreeClose(Btree *p){
|
||||
if( pBt->xFreeSchema && pBt->pSchema ){
|
||||
pBt->xFreeSchema(pBt->pSchema);
|
||||
}
|
||||
sqlite3_free(pBt->pSchema);
|
||||
sqlite3DbFree(0, pBt->pSchema);
|
||||
freeTempSpace(pBt);
|
||||
sqlite3_free(pBt);
|
||||
}
|
||||
@@ -2116,7 +2130,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
((pageSize-1)&pageSize)==0 ){
|
||||
assert( (pageSize & 7)==0 );
|
||||
assert( !pBt->pPage1 && !pBt->pCursor );
|
||||
pBt->pageSize = (u16)pageSize;
|
||||
pBt->pageSize = (u32)pageSize;
|
||||
freeTempSpace(pBt);
|
||||
}
|
||||
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, nReserve);
|
||||
@@ -2251,15 +2265,13 @@ static int lockBtree(BtShared *pBt){
|
||||
** a valid database file.
|
||||
*/
|
||||
nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
|
||||
if( (rc = sqlite3PagerPagecount(pBt->pPager, &nPageFile))!=SQLITE_OK ){;
|
||||
goto page1_init_failed;
|
||||
}
|
||||
sqlite3PagerPagecount(pBt->pPager, &nPageFile);
|
||||
if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
|
||||
nPage = nPageFile;
|
||||
}
|
||||
if( nPage>0 ){
|
||||
int pageSize;
|
||||
int usableSize;
|
||||
u32 pageSize;
|
||||
u32 usableSize;
|
||||
u8 *page1 = pPage1->aData;
|
||||
rc = SQLITE_NOTADB;
|
||||
if( memcmp(page1, zMagicHeader, 16)!=0 ){
|
||||
@@ -2310,15 +2322,16 @@ static int lockBtree(BtShared *pBt){
|
||||
if( memcmp(&page1[21], "\100\040\040",3)!=0 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
pageSize = get2byte(&page1[16]);
|
||||
if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ||
|
||||
(SQLITE_MAX_PAGE_SIZE<32768 && pageSize>SQLITE_MAX_PAGE_SIZE)
|
||||
pageSize = (page1[16]<<8) | (page1[17]<<16);
|
||||
if( ((pageSize-1)&pageSize)!=0
|
||||
|| pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| pageSize<=256
|
||||
){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
assert( (pageSize & 7)==0 );
|
||||
usableSize = pageSize - page1[20];
|
||||
if( pageSize!=pBt->pageSize ){
|
||||
if( (u32)pageSize!=pBt->pageSize ){
|
||||
/* After reading the first page of the database assuming a page size
|
||||
** of BtShared.pageSize, we have discovered that the page-size is
|
||||
** actually pageSize. Unlock the database, leave pBt->pPage1 at
|
||||
@@ -2326,8 +2339,8 @@ static int lockBtree(BtShared *pBt){
|
||||
** again with the correct page-size.
|
||||
*/
|
||||
releasePage(pPage1);
|
||||
pBt->usableSize = (u16)usableSize;
|
||||
pBt->pageSize = (u16)pageSize;
|
||||
pBt->usableSize = usableSize;
|
||||
pBt->pageSize = pageSize;
|
||||
freeTempSpace(pBt);
|
||||
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
|
||||
pageSize-usableSize);
|
||||
@@ -2340,8 +2353,8 @@ static int lockBtree(BtShared *pBt){
|
||||
if( usableSize<480 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
pBt->pageSize = (u16)pageSize;
|
||||
pBt->usableSize = (u16)usableSize;
|
||||
pBt->pageSize = pageSize;
|
||||
pBt->usableSize = usableSize;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
pBt->autoVacuum = (get4byte(&page1[36 + 4*4])?1:0);
|
||||
pBt->incrVacuum = (get4byte(&page1[36 + 7*4])?1:0);
|
||||
@@ -2357,14 +2370,14 @@ static int lockBtree(BtShared *pBt){
|
||||
** 9-byte nKey value
|
||||
** 4-byte nData value
|
||||
** 4-byte overflow page pointer
|
||||
** So a cell consists of a 2-byte poiner, a header which is as much as
|
||||
** So a cell consists of a 2-byte pointer, a header which is as much as
|
||||
** 17 bytes long, 0 to N bytes of payload, and an optional 4 byte overflow
|
||||
** page pointer.
|
||||
*/
|
||||
pBt->maxLocal = (pBt->usableSize-12)*64/255 - 23;
|
||||
pBt->minLocal = (pBt->usableSize-12)*32/255 - 23;
|
||||
pBt->maxLeaf = pBt->usableSize - 35;
|
||||
pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
|
||||
pBt->maxLocal = (u16)((pBt->usableSize-12)*64/255 - 23);
|
||||
pBt->minLocal = (u16)((pBt->usableSize-12)*32/255 - 23);
|
||||
pBt->maxLeaf = (u16)(pBt->usableSize - 35);
|
||||
pBt->minLeaf = (u16)((pBt->usableSize-12)*32/255 - 23);
|
||||
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
|
||||
pBt->pPage1 = pPage1;
|
||||
pBt->nPage = nPage;
|
||||
@@ -2417,7 +2430,8 @@ static int newDatabase(BtShared *pBt){
|
||||
if( rc ) return rc;
|
||||
memcpy(data, zMagicHeader, sizeof(zMagicHeader));
|
||||
assert( sizeof(zMagicHeader)==16 );
|
||||
put2byte(&data[16], pBt->pageSize);
|
||||
data[16] = (u8)((pBt->pageSize>>8)&0xff);
|
||||
data[17] = (u8)((pBt->pageSize>>16)&0xff);
|
||||
data[18] = 1;
|
||||
data[19] = 1;
|
||||
assert( pBt->usableSize<=pBt->pageSize && pBt->usableSize+255>=pBt->pageSize);
|
||||
@@ -3328,9 +3342,11 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
||||
if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
|
||||
rc = newDatabase(pBt);
|
||||
pBt->nPage = get4byte(28 + pBt->pPage1->aData);
|
||||
if( pBt->nPage==0 ){
|
||||
sqlite3PagerPagecount(pBt->pPager, (int*)&pBt->nPage);
|
||||
}
|
||||
|
||||
/* The database size was written into the offset 28 of the header
|
||||
** when the transaction started, so we know that the value at offset
|
||||
** 28 is nonzero. */
|
||||
assert( pBt->nPage>0 );
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
}
|
||||
@@ -4426,9 +4442,9 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
pCur->validNKey = 1;
|
||||
pCur->info.nKey = nCellKey;
|
||||
}else{
|
||||
/* The maximum supported page-size is 32768 bytes. This means that
|
||||
/* The maximum supported page-size is 65536 bytes. This means that
|
||||
** the maximum number of record bytes stored on an index B-Tree
|
||||
** page is at most 8198 bytes, which may be stored as a 2-byte
|
||||
** page is less than 16384 bytes and may be stored as a 2-byte
|
||||
** varint. This information is used to attempt to avoid parsing
|
||||
** the entire cell by checking for the cases where the record is
|
||||
** stored entirely within the b-tree page by inspecting the first
|
||||
@@ -4791,6 +4807,10 @@ static int allocateBtreePage(
|
||||
if( !pPrevTrunk ){
|
||||
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
|
||||
}else{
|
||||
rc = sqlite3PagerWrite(pPrevTrunk->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto end_allocate_page;
|
||||
}
|
||||
memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4);
|
||||
}
|
||||
}else{
|
||||
@@ -5097,7 +5117,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
||||
Pgno ovflPgno;
|
||||
int rc;
|
||||
int nOvfl;
|
||||
u16 ovflPageSize;
|
||||
u32 ovflPageSize;
|
||||
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
btreeParseCellPtr(pPage, pCell, &info);
|
||||
@@ -5322,7 +5342,7 @@ static int fillInCell(
|
||||
*/
|
||||
static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
int i; /* Loop counter */
|
||||
int pc; /* Offset to cell content of cell being deleted */
|
||||
u32 pc; /* Offset to cell content of cell being deleted */
|
||||
u8 *data; /* pPage->aData */
|
||||
u8 *ptr; /* Used to move bytes around within data[] */
|
||||
int rc; /* The return code */
|
||||
@@ -5340,7 +5360,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
hdr = pPage->hdrOffset;
|
||||
testcase( pc==get2byte(&data[hdr+5]) );
|
||||
testcase( pc+sz==pPage->pBt->usableSize );
|
||||
if( pc < get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
|
||||
if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){
|
||||
*pRC = SQLITE_CORRUPT_BKPT;
|
||||
return;
|
||||
}
|
||||
@@ -5397,7 +5417,7 @@ static void insertCell(
|
||||
if( *pRC ) return;
|
||||
|
||||
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
|
||||
assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 );
|
||||
assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921 );
|
||||
assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
/* The cell should normally be sized correctly. However, when moving a
|
||||
@@ -5477,12 +5497,12 @@ static void assemblePage(
|
||||
|
||||
assert( pPage->nOverflow==0 );
|
||||
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
||||
assert( nCell>=0 && nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 );
|
||||
assert( nCell>=0 && nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=10921);
|
||||
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
||||
|
||||
/* Check that the page has just been zeroed by zeroPage() */
|
||||
assert( pPage->nCell==0 );
|
||||
assert( get2byte(&data[hdr+5])==nUsable );
|
||||
assert( get2byteNotZero(&data[hdr+5])==nUsable );
|
||||
|
||||
pCellptr = &data[pPage->cellOffset + nCell*2];
|
||||
cellbody = nUsable;
|
||||
@@ -5548,6 +5568,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
||||
assert( pPage->nOverflow==1 );
|
||||
|
||||
/* This error condition is now caught prior to reaching this function */
|
||||
if( pPage->nCell<=0 ) return SQLITE_CORRUPT_BKPT;
|
||||
|
||||
/* Allocate a new page. This page will become the right-sibling of
|
||||
@@ -5877,7 +5898,7 @@ static int balance_nonroot(
|
||||
** is allocated. */
|
||||
if( pBt->secureDelete ){
|
||||
int iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
||||
if( (iOff+szNew[i])>pBt->usableSize ){
|
||||
if( (iOff+szNew[i])>(int)pBt->usableSize ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
||||
goto balance_cleanup;
|
||||
@@ -5956,7 +5977,7 @@ static int balance_nonroot(
|
||||
szCell[nCell] = sz;
|
||||
pTemp = &aSpace1[iSpace1];
|
||||
iSpace1 += sz;
|
||||
assert( sz<=pBt->pageSize/4 );
|
||||
assert( sz<=pBt->maxLocal+23 );
|
||||
assert( iSpace1<=pBt->pageSize );
|
||||
memcpy(pTemp, apDiv[i], sz);
|
||||
apCell[nCell] = pTemp+leafCorrection;
|
||||
@@ -6202,7 +6223,7 @@ static int balance_nonroot(
|
||||
}
|
||||
}
|
||||
iOvflSpace += sz;
|
||||
assert( sz<=pBt->pageSize/4 );
|
||||
assert( sz<=pBt->maxLocal+23 );
|
||||
assert( iOvflSpace<=pBt->pageSize );
|
||||
insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc);
|
||||
if( rc!=SQLITE_OK ) goto balance_cleanup;
|
||||
@@ -7446,7 +7467,7 @@ static void checkList(
|
||||
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext);
|
||||
}
|
||||
#endif
|
||||
if( n>pCheck->pBt->usableSize/4-2 ){
|
||||
if( n>(int)pCheck->pBt->usableSize/4-2 ){
|
||||
checkAppendMsg(pCheck, zContext,
|
||||
"freelist leaf count too big on page %d", iPage);
|
||||
N--;
|
||||
@@ -7657,7 +7678,7 @@ static int checkTreePage(
|
||||
if( hit==0 ){
|
||||
pCheck->mallocFailed = 1;
|
||||
}else{
|
||||
u16 contentOffset = get2byte(&data[hdr+5]);
|
||||
int contentOffset = get2byteNotZero(&data[hdr+5]);
|
||||
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
memset(hit+contentOffset, 0, usableSize-contentOffset);
|
||||
memset(hit, 1, contentOffset);
|
||||
@@ -7665,12 +7686,12 @@ static int checkTreePage(
|
||||
cellStart = hdr + 12 - 4*pPage->leaf;
|
||||
for(i=0; i<nCell; i++){
|
||||
int pc = get2byte(&data[cellStart+i*2]);
|
||||
u16 size = 1024;
|
||||
u32 size = 65536;
|
||||
int j;
|
||||
if( pc<=usableSize-4 ){
|
||||
size = cellSizePtr(pPage, &data[pc]);
|
||||
}
|
||||
if( (pc+size-1)>=usableSize ){
|
||||
if( (int)(pc+size-1)>=usableSize ){
|
||||
checkAppendMsg(pCheck, 0,
|
||||
"Corruption detected in cell %d on page %d",i,iPage);
|
||||
}else{
|
||||
@@ -7763,6 +7784,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
sCheck.anRef[i] = 1;
|
||||
}
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
|
||||
sCheck.errMsg.useMalloc = 2;
|
||||
|
||||
/* Check the integrity of the freelist
|
||||
*/
|
||||
@@ -7861,6 +7883,29 @@ int sqlite3BtreeIsInTrans(Btree *p){
|
||||
return (p && (p->inTrans==TRANS_WRITE));
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** Run a checkpoint on the Btree passed as the first argument.
|
||||
**
|
||||
** Return SQLITE_LOCKED if this or any other connection has an open
|
||||
** transaction on the shared-cache the argument Btree is connected to.
|
||||
*/
|
||||
int sqlite3BtreeCheckpoint(Btree *p){
|
||||
int rc = SQLITE_OK;
|
||||
if( p ){
|
||||
BtShared *pBt = p->pBt;
|
||||
sqlite3BtreeEnter(p);
|
||||
if( pBt->inTransaction!=TRANS_NONE ){
|
||||
rc = SQLITE_LOCKED;
|
||||
}else{
|
||||
rc = sqlite3PagerCheckpoint(pBt->pPager);
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Return non-zero if a read (or write) transaction is active.
|
||||
*/
|
||||
@@ -7900,7 +7945,7 @@ void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){
|
||||
BtShared *pBt = p->pBt;
|
||||
sqlite3BtreeEnter(p);
|
||||
if( !pBt->pSchema && nBytes ){
|
||||
pBt->pSchema = sqlite3MallocZero(nBytes);
|
||||
pBt->pSchema = sqlite3DbMallocZero(0, nBytes);
|
||||
pBt->xFreeSchema = xFree;
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
|
||||
@@ -201,6 +201,10 @@ int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
||||
void sqlite3BtreeCursorList(Btree*);
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
int sqlite3BtreeCheckpoint(Btree*);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If we are not using shared cache, then there is no need to
|
||||
** use mutexes to access the BtShared structures. So make the
|
||||
|
||||
+3
-3
@@ -46,7 +46,7 @@
|
||||
**
|
||||
** The file is divided into pages. The first page is called page 1,
|
||||
** the second is page 2, and so forth. A page number of zero indicates
|
||||
** "no such page". The page size can be any power of 2 between 512 and 32768.
|
||||
** "no such page". The page size can be any power of 2 between 512 and 65536.
|
||||
** Each page can be either a btree page, a freelist page, an overflow
|
||||
** page, or a pointer-map page.
|
||||
**
|
||||
@@ -413,14 +413,14 @@ struct BtShared {
|
||||
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||
#endif
|
||||
u16 pageSize; /* Total number of bytes on a page */
|
||||
u16 usableSize; /* Number of usable bytes on each page */
|
||||
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) */
|
||||
u32 nPage; /* Number of pages in the database */
|
||||
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
|
||||
|
||||
+33
-52
@@ -345,33 +345,14 @@ Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const char *zDb){
|
||||
/*
|
||||
** Reclaim the memory used by an index
|
||||
*/
|
||||
static void freeIndex(Index *p){
|
||||
sqlite3 *db = p->pTable->dbMem;
|
||||
static void freeIndex(sqlite3 *db, Index *p){
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
sqlite3DeleteIndexSamples(p);
|
||||
sqlite3DeleteIndexSamples(db, p);
|
||||
#endif
|
||||
sqlite3DbFree(db, p->zColAff);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove the given index from the index hash table, and free
|
||||
** its memory structures.
|
||||
**
|
||||
** The index is removed from the database hash tables but
|
||||
** it is not unlinked from the Table that it indexes.
|
||||
** Unlinking from the Table must be done by the calling function.
|
||||
*/
|
||||
static void sqlite3DeleteIndex(Index *p){
|
||||
Index *pOld;
|
||||
const char *zName = p->zName;
|
||||
|
||||
pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName,
|
||||
sqlite3Strlen30(zName), 0);
|
||||
assert( pOld==0 || pOld==p );
|
||||
freeIndex(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** For the index called zIdxName which is found in the database iDb,
|
||||
** unlike that index from its Table then remove the index from
|
||||
@@ -398,7 +379,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
||||
p->pNext = pIndex->pNext;
|
||||
}
|
||||
}
|
||||
freeIndex(pIndex);
|
||||
freeIndex(db, pIndex);
|
||||
}
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
@@ -469,13 +450,12 @@ void sqlite3CommitInternalChanges(sqlite3 *db){
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear the column names from a table or view.
|
||||
** Delete memory allocated for the column names of a table or view (the
|
||||
** Table.aCol[] array).
|
||||
*/
|
||||
static void sqliteResetColumnNames(Table *pTable){
|
||||
static void sqliteDeleteColumnNames(sqlite3 *db, Table *pTable){
|
||||
int i;
|
||||
Column *pCol;
|
||||
sqlite3 *db = pTable->dbMem;
|
||||
testcase( db==0 );
|
||||
assert( pTable!=0 );
|
||||
if( (pCol = pTable->aCol)!=0 ){
|
||||
for(i=0; i<pTable->nCol; i++, pCol++){
|
||||
@@ -487,8 +467,6 @@ static void sqliteResetColumnNames(Table *pTable){
|
||||
}
|
||||
sqlite3DbFree(db, pTable->aCol);
|
||||
}
|
||||
pTable->aCol = 0;
|
||||
pTable->nCol = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -500,42 +478,44 @@ static void sqliteResetColumnNames(Table *pTable){
|
||||
** memory structures of the indices and foreign keys associated with
|
||||
** the table.
|
||||
*/
|
||||
void sqlite3DeleteTable(Table *pTable){
|
||||
void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
||||
Index *pIndex, *pNext;
|
||||
sqlite3 *db;
|
||||
|
||||
if( pTable==0 ) return;
|
||||
db = pTable->dbMem;
|
||||
testcase( db==0 );
|
||||
assert( !pTable || pTable->nRef>0 );
|
||||
|
||||
/* Do not delete the table until the reference count reaches zero. */
|
||||
pTable->nRef--;
|
||||
if( pTable->nRef>0 ){
|
||||
return;
|
||||
}
|
||||
assert( pTable->nRef==0 );
|
||||
if( !pTable ) return;
|
||||
if( ((!db || db->pnBytesFreed==0) && (--pTable->nRef)>0) ) return;
|
||||
|
||||
/* Delete all indices associated with this table
|
||||
*/
|
||||
/* Delete all indices associated with this table. */
|
||||
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
||||
pNext = pIndex->pNext;
|
||||
assert( pIndex->pSchema==pTable->pSchema );
|
||||
sqlite3DeleteIndex(pIndex);
|
||||
if( !db || db->pnBytesFreed==0 ){
|
||||
char *zName = pIndex->zName;
|
||||
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
|
||||
&pIndex->pSchema->idxHash, zName, sqlite3Strlen30(zName), 0
|
||||
);
|
||||
assert( pOld==pIndex || pOld==0 );
|
||||
}
|
||||
freeIndex(db, pIndex);
|
||||
}
|
||||
|
||||
/* Delete any foreign keys attached to this table. */
|
||||
sqlite3FkDelete(pTable);
|
||||
sqlite3FkDelete(db, pTable);
|
||||
|
||||
/* Delete the Table structure itself.
|
||||
*/
|
||||
sqliteResetColumnNames(pTable);
|
||||
sqliteDeleteColumnNames(db, pTable);
|
||||
sqlite3DbFree(db, pTable->zName);
|
||||
sqlite3DbFree(db, pTable->zColAff);
|
||||
sqlite3SelectDelete(db, pTable->pSelect);
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
sqlite3ExprDelete(db, pTable->pCheck);
|
||||
#endif
|
||||
sqlite3VtabClear(pTable);
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3VtabClear(db, pTable);
|
||||
#endif
|
||||
sqlite3DbFree(db, pTable);
|
||||
}
|
||||
|
||||
@@ -554,7 +534,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
|
||||
pDb = &db->aDb[iDb];
|
||||
p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName,
|
||||
sqlite3Strlen30(zTabName),0);
|
||||
sqlite3DeleteTable(p);
|
||||
sqlite3DeleteTable(db, p);
|
||||
db->flags |= SQLITE_InternChanges;
|
||||
}
|
||||
|
||||
@@ -822,7 +802,6 @@ void sqlite3StartTable(
|
||||
pTable->iPKey = -1;
|
||||
pTable->pSchema = db->aDb[iDb].pSchema;
|
||||
pTable->nRef = 1;
|
||||
pTable->dbMem = 0;
|
||||
assert( pParse->pNewTable==0 );
|
||||
pParse->pNewTable = pTable;
|
||||
|
||||
@@ -1374,7 +1353,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
||||
zEnd = "\n)";
|
||||
}
|
||||
n += 35 + 6*p->nCol;
|
||||
zStmt = sqlite3Malloc( n );
|
||||
zStmt = sqlite3DbMallocRaw(0, n);
|
||||
if( zStmt==0 ){
|
||||
db->mallocFailed = 1;
|
||||
return 0;
|
||||
@@ -1555,7 +1534,7 @@ void sqlite3EndTable(
|
||||
p->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
sqlite3DeleteTable(pSelTab);
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1799,7 +1778,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
pTable->aCol = pSelTab->aCol;
|
||||
pSelTab->nCol = 0;
|
||||
pSelTab->aCol = 0;
|
||||
sqlite3DeleteTable(pSelTab);
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
pTable->pSchema->flags |= DB_UnresetViews;
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
@@ -1824,7 +1803,9 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
||||
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
|
||||
Table *pTab = sqliteHashData(i);
|
||||
if( pTab->pSelect ){
|
||||
sqliteResetColumnNames(pTab);
|
||||
sqliteDeleteColumnNames(db, pTab);
|
||||
pTab->aCol = 0;
|
||||
pTab->nCol = 0;
|
||||
}
|
||||
}
|
||||
DbClearProperty(db, idx, DB_UnresetViews);
|
||||
@@ -2821,7 +2802,7 @@ Index *sqlite3CreateIndex(
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
if( pIndex ){
|
||||
sqlite3_free(pIndex->zColAff);
|
||||
sqlite3DbFree(db, pIndex->zColAff);
|
||||
sqlite3DbFree(db, pIndex);
|
||||
}
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
@@ -3200,7 +3181,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
||||
sqlite3DbFree(db, pItem->zName);
|
||||
sqlite3DbFree(db, pItem->zAlias);
|
||||
sqlite3DbFree(db, pItem->zIndex);
|
||||
sqlite3DeleteTable(pItem->pTab);
|
||||
sqlite3DeleteTable(db, pItem->pTab);
|
||||
sqlite3SelectDelete(db, pItem->pSelect);
|
||||
sqlite3ExprDelete(db, pItem->pOn);
|
||||
sqlite3IdListDelete(db, pItem->pUsing);
|
||||
|
||||
+2
-3
@@ -422,8 +422,7 @@ void sqlite3SchemaFree(void *p){
|
||||
sqlite3HashInit(&pSchema->tblHash);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
assert( pTab->dbMem==0 );
|
||||
sqlite3DeleteTable(pTab);
|
||||
sqlite3DeleteTable(0, pTab);
|
||||
}
|
||||
sqlite3HashClear(&temp1);
|
||||
sqlite3HashClear(&pSchema->fkeyHash);
|
||||
@@ -440,7 +439,7 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
|
||||
if( pBt ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaFree);
|
||||
}else{
|
||||
p = (Schema *)sqlite3MallocZero(sizeof(Schema));
|
||||
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
|
||||
}
|
||||
if( !p ){
|
||||
db->mallocFailed = 1;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
||||
Table *pTab;
|
||||
assert( pItem && pSrc->nSrc==1 );
|
||||
pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
|
||||
sqlite3DeleteTable(pItem->pTab);
|
||||
sqlite3DeleteTable(pParse->db, pItem->pTab);
|
||||
pItem->pTab = pTab;
|
||||
if( pTab ){
|
||||
pTab->nRef++;
|
||||
|
||||
+19
-11
@@ -55,6 +55,18 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
return pExpr->affinity;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the explicit collating sequence for an expression to the
|
||||
** collating sequence supplied in the second argument.
|
||||
*/
|
||||
Expr *sqlite3ExprSetColl(Expr *pExpr, CollSeq *pColl){
|
||||
if( pExpr && pColl ){
|
||||
pExpr->pColl = pColl;
|
||||
pExpr->flags |= EP_ExpCollate;
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the collating sequence for expression pExpr to be the collating
|
||||
** sequence named by pToken. Return a pointer to the revised expression.
|
||||
@@ -62,18 +74,13 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
** flag. An explicit collating sequence will override implicit
|
||||
** collating sequences.
|
||||
*/
|
||||
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
char *zColl = 0; /* Dequoted name of collation sequence */
|
||||
CollSeq *pColl;
|
||||
sqlite3 *db = pParse->db;
|
||||
zColl = sqlite3NameFromToken(db, pCollName);
|
||||
if( pExpr && zColl ){
|
||||
pColl = sqlite3LocateCollSeq(pParse, zColl);
|
||||
if( pColl ){
|
||||
pExpr->pColl = pColl;
|
||||
pExpr->flags |= EP_ExpCollate;
|
||||
}
|
||||
}
|
||||
pColl = sqlite3LocateCollSeq(pParse, zColl);
|
||||
sqlite3ExprSetColl(pExpr, pColl);
|
||||
sqlite3DbFree(db, zColl);
|
||||
return pExpr;
|
||||
}
|
||||
@@ -547,18 +554,19 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
}else if( z[0]=='?' ){
|
||||
/* Wildcard of the form "?nnn". Convert "nnn" to an integer and
|
||||
** use it as the variable number */
|
||||
int i = atoi((char*)&z[1]);
|
||||
i64 i;
|
||||
int bOk = sqlite3Atoi64(&z[1], &i);
|
||||
pExpr->iColumn = (ynVar)i;
|
||||
testcase( i==0 );
|
||||
testcase( i==1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
|
||||
testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
|
||||
if( i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
||||
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
||||
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
|
||||
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
|
||||
}
|
||||
if( i>pParse->nVar ){
|
||||
pParse->nVar = i;
|
||||
pParse->nVar = (int)i;
|
||||
}
|
||||
}else{
|
||||
/* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable
|
||||
|
||||
+22
-23
@@ -500,7 +500,8 @@ static void fkScanChildren(
|
||||
if( pIdx ){
|
||||
Column *pCol;
|
||||
iCol = pIdx->aiColumn[i];
|
||||
pCol = &pIdx->pTable->aCol[iCol];
|
||||
pCol = &pTab->aCol[iCol];
|
||||
if( pTab->iPKey==iCol ) iCol = -1;
|
||||
pLeft->iTable = regData+iCol+1;
|
||||
pLeft->affinity = pCol->affinity;
|
||||
pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl);
|
||||
@@ -1061,11 +1062,7 @@ static Trigger *fkActionTrigger(
|
||||
pWhere = 0;
|
||||
}
|
||||
|
||||
/* In the current implementation, pTab->dbMem==0 for all tables except
|
||||
** for temporary tables used to describe subqueries. And temporary
|
||||
** tables do not have foreign key constraints. Hence, pTab->dbMem
|
||||
** should always be 0 there.
|
||||
*/
|
||||
/* Disable lookaside memory allocation */
|
||||
enableLookaside = db->lookaside.bEnabled;
|
||||
db->lookaside.bEnabled = 0;
|
||||
|
||||
@@ -1155,37 +1152,39 @@ void sqlite3FkActions(
|
||||
** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash
|
||||
** hash table.
|
||||
*/
|
||||
void sqlite3FkDelete(Table *pTab){
|
||||
void sqlite3FkDelete(sqlite3 *db, Table *pTab){
|
||||
FKey *pFKey; /* Iterator variable */
|
||||
FKey *pNext; /* Copy of pFKey->pNextFrom */
|
||||
|
||||
for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
|
||||
|
||||
/* Remove the FK from the fkeyHash hash table. */
|
||||
if( pFKey->pPrevTo ){
|
||||
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
|
||||
}else{
|
||||
void *data = (void *)pFKey->pNextTo;
|
||||
const char *z = (data ? pFKey->pNextTo->zTo : pFKey->zTo);
|
||||
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), data);
|
||||
if( !db || db->pnBytesFreed==0 ){
|
||||
if( pFKey->pPrevTo ){
|
||||
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
|
||||
}else{
|
||||
void *p = (void *)pFKey->pNextTo;
|
||||
const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
|
||||
sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), p);
|
||||
}
|
||||
if( pFKey->pNextTo ){
|
||||
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
|
||||
}
|
||||
}
|
||||
if( pFKey->pNextTo ){
|
||||
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
|
||||
}
|
||||
|
||||
/* Delete any triggers created to implement actions for this FK. */
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
fkTriggerDelete(pTab->dbMem, pFKey->apTrigger[0]);
|
||||
fkTriggerDelete(pTab->dbMem, pFKey->apTrigger[1]);
|
||||
#endif
|
||||
|
||||
/* EV: R-30323-21917 Each foreign key constraint in SQLite is
|
||||
** classified as either immediate or deferred.
|
||||
*/
|
||||
assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 );
|
||||
|
||||
/* Delete any triggers created to implement actions for this FK. */
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
fkTriggerDelete(db, pFKey->apTrigger[0]);
|
||||
fkTriggerDelete(db, pFKey->apTrigger[1]);
|
||||
#endif
|
||||
|
||||
pNext = pFKey->pNextFrom;
|
||||
sqlite3DbFree(pTab->dbMem, pFKey);
|
||||
sqlite3DbFree(db, pFKey);
|
||||
}
|
||||
}
|
||||
#endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */
|
||||
|
||||
+10
-7
@@ -788,8 +788,10 @@ static void compileoptionusedFunc(
|
||||
const char *zOptName;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
/* IMP: R-xxxx This function is an SQL wrapper around the
|
||||
** sqlite3_compileoption_used() C interface. */
|
||||
/* IMP: R-39564-36305 The sqlite_compileoption_used() SQL
|
||||
** function is a wrapper around the sqlite3_compileoption_used() C/C++
|
||||
** function.
|
||||
*/
|
||||
if( (zOptName = (const char*)sqlite3_value_text(argv[0]))!=0 ){
|
||||
sqlite3_result_int(context, sqlite3_compileoption_used(zOptName));
|
||||
}
|
||||
@@ -810,8 +812,9 @@ static void compileoptiongetFunc(
|
||||
int n;
|
||||
assert( argc==1 );
|
||||
UNUSED_PARAMETER(argc);
|
||||
/* IMP: R-xxxx This function is an SQL wrapper around the
|
||||
** sqlite3_compileoption_get() C interface. */
|
||||
/* IMP: R-04922-24076 The sqlite_compileoption_get() SQL function
|
||||
** is a wrapper around the sqlite3_compileoption_get() C/C++ function.
|
||||
*/
|
||||
n = sqlite3_value_int(argv[0]);
|
||||
sqlite3_result_text(context, sqlite3_compileoption_get(n), -1, SQLITE_STATIC);
|
||||
}
|
||||
@@ -1010,14 +1013,14 @@ static void replaceFunc(
|
||||
testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
|
||||
if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
sqlite3DbFree(db, zOut);
|
||||
sqlite3_free(zOut);
|
||||
return;
|
||||
}
|
||||
zOld = zOut;
|
||||
zOut = sqlite3_realloc(zOut, (int)nOut);
|
||||
if( zOut==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
sqlite3DbFree(db, zOld);
|
||||
sqlite3_free(zOld);
|
||||
return;
|
||||
}
|
||||
memcpy(&zOut[j], zRep, nRep);
|
||||
@@ -1378,7 +1381,7 @@ static void groupConcatStep(
|
||||
if( pAccum ){
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
int firstTerm = pAccum->useMalloc==0;
|
||||
pAccum->useMalloc = 1;
|
||||
pAccum->useMalloc = 2;
|
||||
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
|
||||
if( !firstTerm ){
|
||||
if( argc==2 ){
|
||||
|
||||
+3
-2
@@ -67,7 +67,7 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
int n;
|
||||
Table *pTab = pIdx->pTable;
|
||||
sqlite3 *db = sqlite3VdbeDb(v);
|
||||
pIdx->zColAff = (char *)sqlite3Malloc(pIdx->nColumn+2);
|
||||
pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+2);
|
||||
if( !pIdx->zColAff ){
|
||||
db->mallocFailed = 1;
|
||||
return 0;
|
||||
@@ -109,7 +109,7 @@ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){
|
||||
int i;
|
||||
sqlite3 *db = sqlite3VdbeDb(v);
|
||||
|
||||
zColAff = (char *)sqlite3Malloc(pTab->nCol+1);
|
||||
zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
|
||||
if( !zColAff ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
@@ -1220,6 +1220,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
if( onError==OE_Ignore ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
}else{
|
||||
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
|
||||
sqlite3HaltConstraint(pParse, onError, 0, 0);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
|
||||
+2
-6
@@ -376,13 +376,11 @@ static int sqlite3LoadExtension(
|
||||
handle = sqlite3OsDlOpen(pVfs, zFile);
|
||||
if( handle==0 ){
|
||||
if( pzErrMsg ){
|
||||
zErrmsg = sqlite3StackAllocZero(db, nMsg);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
if( zErrmsg ){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
"unable to open shared library [%s]", zFile);
|
||||
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
||||
*pzErrMsg = sqlite3DbStrDup(0, zErrmsg);
|
||||
sqlite3StackFree(db, zErrmsg);
|
||||
}
|
||||
}
|
||||
return SQLITE_ERROR;
|
||||
@@ -391,13 +389,11 @@ static int sqlite3LoadExtension(
|
||||
sqlite3OsDlSym(pVfs, handle, zProc);
|
||||
if( xInit==0 ){
|
||||
if( pzErrMsg ){
|
||||
zErrmsg = sqlite3StackAllocZero(db, nMsg);
|
||||
*pzErrMsg = zErrmsg = sqlite3_malloc(nMsg);
|
||||
if( zErrmsg ){
|
||||
sqlite3_snprintf(nMsg, zErrmsg,
|
||||
"no entry point [%s] in shared library [%s]", zProc,zFile);
|
||||
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
||||
*pzErrMsg = sqlite3DbStrDup(0, zErrmsg);
|
||||
sqlite3StackFree(db, zErrmsg);
|
||||
}
|
||||
sqlite3OsDlClose(pVfs, handle);
|
||||
}
|
||||
|
||||
+1
-10
@@ -1308,16 +1308,7 @@ int sqlite3Checkpoint(sqlite3 *db, int iDb){
|
||||
|
||||
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
|
||||
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
if( sqlite3BtreeIsInReadTrans(pBt) ){
|
||||
rc = SQLITE_LOCKED;
|
||||
}else{
|
||||
sqlite3BtreeEnter(pBt);
|
||||
rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
|
||||
sqlite3BtreeLeave(pBt);
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-18
@@ -251,6 +251,7 @@ static int mallocWithAlarm(int n, void **pp){
|
||||
if( p ){
|
||||
nFull = sqlite3MallocSize(p);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nFull);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, 1);
|
||||
}
|
||||
*pp = p;
|
||||
return nFull;
|
||||
@@ -368,12 +369,14 @@ void sqlite3ScratchFree(void *p){
|
||||
|| p<sqlite3GlobalConfig.pScratch
|
||||
|| p>=(void*)mem0.aScratchFree ){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
|
||||
assert( sqlite3MemdebugNoType(p, ~MEMTYPE_SCRATCH) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
if( sqlite3GlobalConfig.bMemstat ){
|
||||
int iSize = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_SCRATCH_OVERFLOW, -iSize);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -iSize);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
|
||||
sqlite3GlobalConfig.m.xFree(p);
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
}else{
|
||||
@@ -408,7 +411,7 @@ void sqlite3ScratchFree(void *p){
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_LOOKASIDE
|
||||
static int isLookaside(sqlite3 *db, void *p){
|
||||
return db && p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
|
||||
return p && p>=db->lookaside.pStart && p<db->lookaside.pEnd;
|
||||
}
|
||||
#else
|
||||
#define isLookaside(A,B) 0
|
||||
@@ -420,15 +423,17 @@ static int isLookaside(sqlite3 *db, void *p){
|
||||
*/
|
||||
int sqlite3MallocSize(void *p){
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( isLookaside(db, p) ){
|
||||
if( db && isLookaside(db, p) ){
|
||||
return db->lookaside.sz;
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p,
|
||||
db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
|
||||
return sqlite3GlobalConfig.m.xSize(p);
|
||||
}
|
||||
}
|
||||
@@ -438,10 +443,12 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
||||
*/
|
||||
void sqlite3_free(void *p){
|
||||
if( p==0 ) return;
|
||||
assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
if( sqlite3GlobalConfig.bMemstat ){
|
||||
sqlite3_mutex_enter(mem0.mutex);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
|
||||
sqlite3StatusAdd(SQLITE_STATUS_MALLOC_COUNT, -1);
|
||||
sqlite3GlobalConfig.m.xFree(p);
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
}else{
|
||||
@@ -455,16 +462,24 @@ void sqlite3_free(void *p){
|
||||
*/
|
||||
void sqlite3DbFree(sqlite3 *db, void *p){
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
if( isLookaside(db, p) ){
|
||||
LookasideSlot *pBuf = (LookasideSlot*)p;
|
||||
pBuf->pNext = db->lookaside.pFree;
|
||||
db->lookaside.pFree = pBuf;
|
||||
db->lookaside.nOut--;
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
sqlite3_free(p);
|
||||
if( db ){
|
||||
if( db->pnBytesFreed ){
|
||||
*db->pnBytesFreed += sqlite3DbMallocSize(db, p);
|
||||
return;
|
||||
}
|
||||
if( isLookaside(db, p) ){
|
||||
LookasideSlot *pBuf = (LookasideSlot*)p;
|
||||
pBuf->pNext = db->lookaside.pFree;
|
||||
db->lookaside.pFree = pBuf;
|
||||
db->lookaside.nOut--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
assert( db!=0 || sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -496,6 +511,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
|
||||
sqlite3MallocAlarm(nNew-nOld);
|
||||
}
|
||||
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
|
||||
assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) );
|
||||
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
||||
if( pNew==0 && mem0.alarmCallback ){
|
||||
sqlite3MallocAlarm(nBytes);
|
||||
@@ -568,6 +584,7 @@ void *sqlite3DbMallocZero(sqlite3 *db, int n){
|
||||
void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
||||
void *p;
|
||||
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
||||
assert( db==0 || db->pnBytesFreed==0 );
|
||||
#ifndef SQLITE_OMIT_LOOKASIDE
|
||||
if( db ){
|
||||
LookasideSlot *pBuf;
|
||||
@@ -593,8 +610,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
|
||||
if( !p && db ){
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3MemdebugSetType(p,
|
||||
(db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP);
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_DB |
|
||||
((db && db->lookaside.bEnabled) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -620,14 +637,16 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_LOOKASIDE|MEMTYPE_HEAP) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
pNew = sqlite3_realloc(p, n);
|
||||
if( !pNew ){
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
|
||||
db->mallocFailed = 1;
|
||||
}
|
||||
sqlite3MemdebugSetType(pNew,
|
||||
db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP);
|
||||
sqlite3MemdebugSetType(pNew, MEMTYPE_DB |
|
||||
(db->lookaside.bEnabled ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP));
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
|
||||
+24
-9
@@ -378,7 +378,7 @@ void sqlite3MemSetDefault(void){
|
||||
** Set the "type" of an allocation.
|
||||
*/
|
||||
void sqlite3MemdebugSetType(void *p, u8 eType){
|
||||
if( p ){
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD );
|
||||
@@ -397,23 +397,38 @@ void sqlite3MemdebugSetType(void *p, u8 eType){
|
||||
*/
|
||||
int sqlite3MemdebugHasType(void *p, u8 eType){
|
||||
int rc = 1;
|
||||
if( p ){
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
||||
assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */
|
||||
if( (pHdr->eType&eType)==0 ){
|
||||
void **pBt;
|
||||
pBt = (void**)pHdr;
|
||||
pBt -= pHdr->nBacktraceSlots;
|
||||
backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr));
|
||||
fprintf(stderr, "\n");
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return TRUE if the mask of type in eType matches no bits of the type of the
|
||||
** allocation p. Also return true if p==NULL.
|
||||
**
|
||||
** This routine is designed for use within an assert() statement, to
|
||||
** verify the type of an allocation. For example:
|
||||
**
|
||||
** assert( sqlite3MemdebugNoType(p, MEMTYPE_DB) );
|
||||
*/
|
||||
int sqlite3MemdebugNoType(void *p, u8 eType){
|
||||
int rc = 1;
|
||||
if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
||||
struct MemBlockHdr *pHdr;
|
||||
pHdr = sqlite3MemsysGetHeader(p);
|
||||
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
||||
if( (pHdr->eType&eType)!=0 ){
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the number of backtrace levels kept for each allocation.
|
||||
|
||||
@@ -235,6 +235,7 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
|
||||
*/
|
||||
pthread_mutex_lock(&p->mutex);
|
||||
#if SQLITE_MUTEX_NREF
|
||||
assert( p->nRef>0 || p->owner==0 );
|
||||
p->owner = pthread_self();
|
||||
p->nRef++;
|
||||
#endif
|
||||
@@ -307,6 +308,7 @@ static void pthreadMutexLeave(sqlite3_mutex *p){
|
||||
assert( pthreadMutexHeld(p) );
|
||||
#if SQLITE_MUTEX_NREF
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ) p->owner = 0;
|
||||
#endif
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
|
||||
|
||||
+3
-1
@@ -220,7 +220,7 @@ static sqlite3_mutex *winMutexAlloc(int iType){
|
||||
*/
|
||||
static void winMutexFree(sqlite3_mutex *p){
|
||||
assert( p );
|
||||
assert( p->nRef==0 );
|
||||
assert( p->nRef==0 && p->owner==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
DeleteCriticalSection(&p->mutex);
|
||||
sqlite3_free(p);
|
||||
@@ -244,6 +244,7 @@ static void winMutexEnter(sqlite3_mutex *p){
|
||||
#endif
|
||||
EnterCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( p->nRef>0 || p->owner==0 );
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
if( p->trace ){
|
||||
@@ -297,6 +298,7 @@ static void winMutexLeave(sqlite3_mutex *p){
|
||||
assert( p->nRef>0 );
|
||||
assert( p->owner==tid );
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ) p->owner = 0;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
|
||||
+1
-1
@@ -255,7 +255,7 @@ void sqlite3ConnectionUnlocked(sqlite3 *db){
|
||||
assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) );
|
||||
assert( nArg<=(int)ArraySize(aStatic) || aArg==aDyn );
|
||||
if( (!aDyn && nArg==(int)ArraySize(aStatic))
|
||||
|| (aDyn && nArg==(int)(sqlite3DbMallocSize(db, aDyn)/sizeof(void*)))
|
||||
|| (aDyn && nArg==(int)(sqlite3MallocSize(aDyn)/sizeof(void*)))
|
||||
){
|
||||
/* The aArg[] array needs to grow. */
|
||||
void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2);
|
||||
|
||||
+75
-14
@@ -210,6 +210,7 @@ struct unixFile {
|
||||
int fileFlags; /* Miscellanous flags */
|
||||
const char *zPath; /* Name of the file */
|
||||
unixShm *pShm; /* Shared memory segment information */
|
||||
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
#endif
|
||||
@@ -2763,6 +2764,7 @@ static int unixWrite(
|
||||
}
|
||||
SimulateIOError(( wrote=(-1), amt=1 ));
|
||||
SimulateDiskfullError(( wrote=0, amt=1 ));
|
||||
|
||||
if( amt>0 ){
|
||||
if( wrote<0 ){
|
||||
/* lastErrno set by seekAndWrite */
|
||||
@@ -2772,6 +2774,7 @@ static int unixWrite(
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -2973,12 +2976,23 @@ static int unixSync(sqlite3_file *id, int flags){
|
||||
** Truncate an open file to a specified size
|
||||
*/
|
||||
static int unixTruncate(sqlite3_file *id, i64 nByte){
|
||||
unixFile *pFile = (unixFile *)id;
|
||||
int rc;
|
||||
assert( id );
|
||||
assert( pFile );
|
||||
SimulateIOError( return SQLITE_IOERR_TRUNCATE );
|
||||
rc = ftruncate(((unixFile*)id)->h, (off_t)nByte);
|
||||
|
||||
/* If the user has configured a chunk-size for this file, truncate the
|
||||
** file so that it consists of an integer number of chunks (i.e. the
|
||||
** actual file size after the operation may be larger than the requested
|
||||
** size).
|
||||
*/
|
||||
if( pFile->szChunk ){
|
||||
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
|
||||
}
|
||||
|
||||
rc = ftruncate(pFile->h, (off_t)nByte);
|
||||
if( rc ){
|
||||
((unixFile*)id)->lastErrno = errno;
|
||||
pFile->lastErrno = errno;
|
||||
return SQLITE_IOERR_TRUNCATE;
|
||||
}else{
|
||||
#ifndef NDEBUG
|
||||
@@ -2989,8 +3003,8 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
||||
** when restoring a database using the backup API from a zero-length
|
||||
** source.
|
||||
*/
|
||||
if( ((unixFile*)id)->inNormalWrite && nByte==0 ){
|
||||
((unixFile*)id)->transCntrChng = 1;
|
||||
if( pFile->inNormalWrite && nByte==0 ){
|
||||
pFile->transCntrChng = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3033,6 +3047,54 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
|
||||
static int proxyFileControl(sqlite3_file*,int,void*);
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
|
||||
** file-control operation.
|
||||
**
|
||||
** If the user has configured a chunk-size for this file, it could be
|
||||
** that the file needs to be extended at this point. Otherwise, the
|
||||
** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix.
|
||||
*/
|
||||
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
||||
if( pFile->szChunk ){
|
||||
i64 nSize; /* Required file size */
|
||||
struct stat buf; /* Used to hold return values of fstat() */
|
||||
|
||||
if( fstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
|
||||
|
||||
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
|
||||
if( nSize>(i64)buf.st_size ){
|
||||
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
|
||||
if( posix_fallocate(pFile->h, buf.st_size, nSize-buf.st_size) ){
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}
|
||||
#else
|
||||
/* If the OS does not have posix_fallocate(), fake it. First use
|
||||
** ftruncate() to set the file size, then write a single byte to
|
||||
** the last byte in each block within the extended region. This
|
||||
** is the same technique used by glibc to implement posix_fallocate()
|
||||
** on systems that do not have a real fallocate() system call.
|
||||
*/
|
||||
int nBlk = buf.st_blksize; /* File-system block size */
|
||||
i64 iWrite; /* Next offset to write to */
|
||||
int nWrite; /* Return value from seekAndWrite() */
|
||||
|
||||
if( ftruncate(pFile->h, nSize) ){
|
||||
pFile->lastErrno = errno;
|
||||
return SQLITE_IOERR_TRUNCATE;
|
||||
}
|
||||
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
|
||||
do {
|
||||
nWrite = seekAndWrite(pFile, iWrite, "", 1);
|
||||
iWrite += nBlk;
|
||||
} while( nWrite==1 && iWrite<nSize );
|
||||
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Information and control of an open file handle.
|
||||
@@ -3047,14 +3109,13 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
*(int*)pArg = ((unixFile*)id)->lastErrno;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
#if 0 /* No performance advantage seen on Linux */
|
||||
sqlite3_int64 szFile = *(sqlite3_int64*)pArg;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
ftruncate(pFile->h, szFile);
|
||||
#endif
|
||||
case SQLITE_FCNTL_CHUNK_SIZE: {
|
||||
((unixFile*)id)->szChunk = *(int *)pArg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@@ -5918,7 +5979,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
||||
pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
|
||||
sqlite3_free(pCtx->conchFile);
|
||||
}
|
||||
sqlite3_free(pCtx->lockProxyPath);
|
||||
sqlite3DbFree(0, pCtx->lockProxyPath);
|
||||
sqlite3_free(pCtx->conchFilePath);
|
||||
sqlite3_free(pCtx);
|
||||
}
|
||||
@@ -6109,9 +6170,9 @@ static int proxyClose(sqlite3_file *id) {
|
||||
if( rc ) return rc;
|
||||
sqlite3_free(conchFile);
|
||||
}
|
||||
sqlite3_free(pCtx->lockProxyPath);
|
||||
sqlite3DbFree(0, pCtx->lockProxyPath);
|
||||
sqlite3_free(pCtx->conchFilePath);
|
||||
sqlite3_free(pCtx->dbPath);
|
||||
sqlite3DbFree(0, pCtx->dbPath);
|
||||
/* restore the original locking context and pMethod then close it */
|
||||
pFile->lockingContext = pCtx->oldLockingContext;
|
||||
pFile->pMethod = pCtx->pOldMethod;
|
||||
|
||||
+95
-65
@@ -108,6 +108,7 @@ struct winFile {
|
||||
DWORD sectorSize; /* Sector size of the device file is on */
|
||||
winShm *pShm; /* Instance of shared memory on this file */
|
||||
const char *zPath; /* Full pathname of this file */
|
||||
int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
|
||||
#if SQLITE_OS_WINCE
|
||||
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
|
||||
HANDLE hMutex; /* Mutex used to control access to shared lock */
|
||||
@@ -620,6 +621,42 @@ static BOOL winceLockFileEx(
|
||||
** by the sqlite3_io_methods object.
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
** Some microsoft compilers lack this definition.
|
||||
*/
|
||||
#ifndef INVALID_SET_FILE_POINTER
|
||||
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Move the current position of the file handle passed as the first
|
||||
** argument to offset iOffset within the file. If successful, return 0.
|
||||
** Otherwise, set pFile->lastErrno and return non-zero.
|
||||
*/
|
||||
static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
|
||||
LONG upperBits; /* Most sig. 32 bits of new offset */
|
||||
LONG lowerBits; /* Least sig. 32 bits of new offset */
|
||||
DWORD dwRet; /* Value returned by SetFilePointer() */
|
||||
|
||||
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
|
||||
lowerBits = (LONG)(iOffset & 0xffffffff);
|
||||
|
||||
/* API oddity: If successful, SetFilePointer() returns a dword
|
||||
** containing the lower 32-bits of the new file-offset. Or, if it fails,
|
||||
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
|
||||
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
|
||||
** whether an error has actually occured, it is also necessary to call
|
||||
** GetLastError().
|
||||
*/
|
||||
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a file.
|
||||
**
|
||||
@@ -662,13 +699,6 @@ static int winClose(sqlite3_file *id){
|
||||
return rc ? SQLITE_OK : SQLITE_IOERR;
|
||||
}
|
||||
|
||||
/*
|
||||
** Some microsoft compilers lack this definition.
|
||||
*/
|
||||
#ifndef INVALID_SET_FILE_POINTER
|
||||
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Read data from a file into a buffer. Return SQLITE_OK if all
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
@@ -680,32 +710,27 @@ static int winRead(
|
||||
int amt, /* Number of bytes to read */
|
||||
sqlite3_int64 offset /* Begin reading at this offset */
|
||||
){
|
||||
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
|
||||
LONG lowerBits = (LONG)(offset & 0xffffffff);
|
||||
DWORD rc;
|
||||
winFile *pFile = (winFile*)id;
|
||||
DWORD error;
|
||||
DWORD got;
|
||||
winFile *pFile = (winFile*)id; /* file handle */
|
||||
DWORD nRead; /* Number of bytes actually read from file */
|
||||
|
||||
assert( id!=0 );
|
||||
SimulateIOError(return SQLITE_IOERR_READ);
|
||||
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
|
||||
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
|
||||
pFile->lastErrno = error;
|
||||
|
||||
if( seekWinFile(pFile, offset) ){
|
||||
return SQLITE_FULL;
|
||||
}
|
||||
if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){
|
||||
if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
return SQLITE_IOERR_READ;
|
||||
}
|
||||
if( got==(DWORD)amt ){
|
||||
return SQLITE_OK;
|
||||
}else{
|
||||
if( nRead<(DWORD)amt ){
|
||||
/* Unread parts of the buffer must be zero-filled */
|
||||
memset(&((char*)pBuf)[got], 0, amt-got);
|
||||
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
|
||||
return SQLITE_IOERR_SHORT_READ;
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -713,47 +738,42 @@ static int winRead(
|
||||
** or some other error code on failure.
|
||||
*/
|
||||
static int winWrite(
|
||||
sqlite3_file *id, /* File to write into */
|
||||
const void *pBuf, /* The bytes to be written */
|
||||
int amt, /* Number of bytes to write */
|
||||
sqlite3_int64 offset /* Offset into the file to begin writing at */
|
||||
sqlite3_file *id, /* File to write into */
|
||||
const void *pBuf, /* The bytes to be written */
|
||||
int amt, /* Number of bytes to write */
|
||||
sqlite3_int64 offset /* Offset into the file to begin writing at */
|
||||
){
|
||||
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
|
||||
LONG lowerBits = (LONG)(offset & 0xffffffff);
|
||||
DWORD rc;
|
||||
winFile *pFile = (winFile*)id;
|
||||
DWORD error;
|
||||
DWORD wrote = 0;
|
||||
int rc; /* True if error has occured, else false */
|
||||
winFile *pFile = (winFile*)id; /* File handle */
|
||||
|
||||
assert( id!=0 );
|
||||
assert( amt>0 );
|
||||
assert( pFile );
|
||||
SimulateIOError(return SQLITE_IOERR_WRITE);
|
||||
SimulateDiskfullError(return SQLITE_FULL);
|
||||
|
||||
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
|
||||
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
|
||||
pFile->lastErrno = error;
|
||||
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
|
||||
return SQLITE_FULL;
|
||||
}else{
|
||||
return SQLITE_IOERR_WRITE;
|
||||
|
||||
rc = seekWinFile(pFile, offset);
|
||||
if( rc==0 ){
|
||||
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
|
||||
int nRem = amt; /* Number of bytes yet to be written */
|
||||
DWORD nWrite; /* Bytes written by each WriteFile() call */
|
||||
|
||||
while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){
|
||||
aRem += nWrite;
|
||||
nRem -= nWrite;
|
||||
}
|
||||
if( nRem>0 ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
assert( amt>0 );
|
||||
while(
|
||||
amt>0
|
||||
&& (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0
|
||||
&& wrote>0
|
||||
){
|
||||
amt -= wrote;
|
||||
pBuf = &((char*)pBuf)[wrote];
|
||||
}
|
||||
if( !rc || amt>(int)wrote ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
|
||||
if( rc ){
|
||||
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
|
||||
return SQLITE_FULL;
|
||||
}else{
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}
|
||||
return SQLITE_IOERR_WRITE;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@@ -762,26 +782,32 @@ static int winWrite(
|
||||
** Truncate an open file to a specified size
|
||||
*/
|
||||
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
|
||||
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
|
||||
LONG lowerBits = (LONG)(nByte & 0xffffffff);
|
||||
DWORD dwRet;
|
||||
winFile *pFile = (winFile*)id;
|
||||
DWORD error;
|
||||
int rc = SQLITE_OK;
|
||||
winFile *pFile = (winFile*)id; /* File handle object */
|
||||
int rc = SQLITE_OK; /* Return code for this function */
|
||||
|
||||
assert( pFile );
|
||||
|
||||
assert( id!=0 );
|
||||
OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
|
||||
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
|
||||
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||
if( dwRet==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
|
||||
pFile->lastErrno = error;
|
||||
|
||||
/* If the user has configured a chunk-size for this file, truncate the
|
||||
** file so that it consists of an integer number of chunks (i.e. the
|
||||
** actual file size after the operation may be larger than the requested
|
||||
** size).
|
||||
*/
|
||||
if( pFile->szChunk ){
|
||||
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
|
||||
}
|
||||
|
||||
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
|
||||
if( seekWinFile(pFile, nByte) ){
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
/* SetEndOfFile will fail if nByte is negative */
|
||||
}else if( !SetEndOfFile(pFile->h) ){
|
||||
}else if( 0==SetEndOfFile(pFile->h) ){
|
||||
pFile->lastErrno = GetLastError();
|
||||
rc = SQLITE_IOERR_TRUNCATE;
|
||||
}
|
||||
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc==SQLITE_OK ? "ok" : "failed"));
|
||||
|
||||
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1146,6 +1172,10 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
*(int*)pArg = (int)((winFile*)id)->lastErrno;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_CHUNK_SIZE: {
|
||||
((winFile*)id)->szChunk = *(int *)pArg;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
sqlite3_int64 sz = *(sqlite3_int64*)pArg;
|
||||
SimulateIOErrorBenign(1);
|
||||
|
||||
+1498
-975
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -99,7 +99,7 @@ int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
||||
|
||||
/* Functions used to configure a Pager object. */
|
||||
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
|
||||
int sqlite3PagerSetPagesize(Pager*, u16*, int);
|
||||
int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
||||
int sqlite3PagerMaxPageCount(Pager*, int);
|
||||
void sqlite3PagerSetCachesize(Pager*, int);
|
||||
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
|
||||
@@ -126,9 +126,10 @@ void *sqlite3PagerGetData(DbPage *);
|
||||
void *sqlite3PagerGetExtra(DbPage *);
|
||||
|
||||
/* Functions used to manage pager transactions and savepoints. */
|
||||
int sqlite3PagerPagecount(Pager*, int*);
|
||||
void sqlite3PagerPagecount(Pager*, int*);
|
||||
int sqlite3PagerBegin(Pager*, int exFlag, int);
|
||||
int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
|
||||
int sqlite3PagerExclusiveLock(Pager*);
|
||||
int sqlite3PagerSync(Pager *pPager);
|
||||
int sqlite3PagerCommitPhaseTwo(Pager*);
|
||||
int sqlite3PagerRollback(Pager*);
|
||||
|
||||
+3
-3
@@ -780,7 +780,7 @@ expr(A) ::= VARIABLE(X). {
|
||||
spanSet(&A, &X, &X);
|
||||
}
|
||||
expr(A) ::= expr(E) COLLATE ids(C). {
|
||||
A.pExpr = sqlite3ExprSetColl(pParse, E.pExpr, &C);
|
||||
A.pExpr = sqlite3ExprSetCollByToken(pParse, E.pExpr, &C);
|
||||
A.zStart = E.zStart;
|
||||
A.zEnd = &C.z[C.n];
|
||||
}
|
||||
@@ -1108,7 +1108,7 @@ idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = 0;
|
||||
if( C.n>0 ){
|
||||
p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
|
||||
sqlite3ExprSetColl(pParse, p, &C);
|
||||
sqlite3ExprSetCollByToken(pParse, p, &C);
|
||||
}
|
||||
A = sqlite3ExprListAppend(pParse,X, p);
|
||||
sqlite3ExprListSetName(pParse,A,&Y,1);
|
||||
@@ -1119,7 +1119,7 @@ idxlist(A) ::= nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = 0;
|
||||
if( C.n>0 ){
|
||||
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
|
||||
sqlite3ExprSetColl(pParse, p, &C);
|
||||
sqlite3ExprSetCollByToken(pParse, p, &C);
|
||||
}
|
||||
A = sqlite3ExprListAppend(pParse,0, p);
|
||||
sqlite3ExprListSetName(pParse, A, &Y, 1);
|
||||
|
||||
+21
-2
@@ -152,11 +152,11 @@ void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
static void *pcache1Alloc(int nByte){
|
||||
void *p;
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
|
||||
if( nByte<=pcache1.szSlot && pcache1.pFree ){
|
||||
assert( pcache1.isInit );
|
||||
p = (PgHdr1 *)pcache1.pFree;
|
||||
pcache1.pFree = pcache1.pFree->pNext;
|
||||
sqlite3StatusSet(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
|
||||
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_USED, 1);
|
||||
}else{
|
||||
|
||||
@@ -200,6 +200,25 @@ static void pcache1Free(void *p){
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
/*
|
||||
** Return the size of a pache allocation
|
||||
*/
|
||||
static int pcache1MemSize(void *p){
|
||||
assert( sqlite3_mutex_held(pcache1.mutex) );
|
||||
if( p>=pcache1.pStart && p<pcache1.pEnd ){
|
||||
return pcache1.szSlot;
|
||||
}else{
|
||||
int iSize;
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
iSize = sqlite3MallocSize(p);
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
|
||||
return iSize;
|
||||
}
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
|
||||
|
||||
/*
|
||||
** Allocate a new page object initially associated with cache pCache.
|
||||
*/
|
||||
@@ -748,7 +767,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex();
|
||||
while( (nReq<0 || nFree<nReq) && (p=pcache1.pLruTail) ){
|
||||
nFree += sqlite3MallocSize(PGHDR1_TO_PAGE(p));
|
||||
nFree += pcache1MemSize(PGHDR1_TO_PAGE(p));
|
||||
pcache1PinPage(p);
|
||||
pcache1RemoveFromHash(p);
|
||||
pcache1FreePage(p);
|
||||
|
||||
+1
-1
@@ -765,7 +765,7 @@ void sqlite3Pragma(
|
||||
}
|
||||
sqlite3_free(sqlite3_temp_directory);
|
||||
if( zRight[0] ){
|
||||
sqlite3_temp_directory = sqlite3DbStrDup(0, zRight);
|
||||
sqlite3_temp_directory = sqlite3_mprintf("%s", zRight);
|
||||
}else{
|
||||
sqlite3_temp_directory = 0;
|
||||
}
|
||||
|
||||
@@ -670,7 +670,6 @@ static int sqlite3Prepare(
|
||||
while( pParse->pTriggerPrg ){
|
||||
TriggerPrg *pT = pParse->pTriggerPrg;
|
||||
pParse->pTriggerPrg = pT->pNext;
|
||||
sqlite3VdbeProgramDelete(db, pT->pProgram, 0);
|
||||
sqlite3DbFree(db, pT);
|
||||
}
|
||||
|
||||
|
||||
+16
-3
@@ -772,7 +772,11 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
|
||||
}else{
|
||||
p->nAlloc = (int)szNew;
|
||||
}
|
||||
zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
|
||||
if( p->useMalloc==1 ){
|
||||
zNew = sqlite3DbMallocRaw(p->db, p->nAlloc );
|
||||
}else{
|
||||
zNew = sqlite3_malloc(p->nAlloc);
|
||||
}
|
||||
if( zNew ){
|
||||
memcpy(zNew, p->zText, p->nChar);
|
||||
sqlite3StrAccumReset(p);
|
||||
@@ -797,7 +801,11 @@ char *sqlite3StrAccumFinish(StrAccum *p){
|
||||
if( p->zText ){
|
||||
p->zText[p->nChar] = 0;
|
||||
if( p->useMalloc && p->zText==p->zBase ){
|
||||
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
|
||||
if( p->useMalloc==1 ){
|
||||
p->zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
|
||||
}else{
|
||||
p->zText = sqlite3_malloc(p->nChar+1);
|
||||
}
|
||||
if( p->zText ){
|
||||
memcpy(p->zText, p->zBase, p->nChar+1);
|
||||
}else{
|
||||
@@ -813,7 +821,11 @@ char *sqlite3StrAccumFinish(StrAccum *p){
|
||||
*/
|
||||
void sqlite3StrAccumReset(StrAccum *p){
|
||||
if( p->zText!=p->zBase ){
|
||||
sqlite3DbFree(p->db, p->zText);
|
||||
if( p->useMalloc==1 ){
|
||||
sqlite3DbFree(p->db, p->zText);
|
||||
}else{
|
||||
sqlite3_free(p->zText);
|
||||
}
|
||||
}
|
||||
p->zText = 0;
|
||||
}
|
||||
@@ -895,6 +907,7 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
sqlite3StrAccumInit(&acc, zBase, sizeof(zBase), SQLITE_MAX_LENGTH);
|
||||
acc.useMalloc = 2;
|
||||
sqlite3VXPrintf(&acc, 0, zFormat, ap);
|
||||
z = sqlite3StrAccumFinish(&acc);
|
||||
return z;
|
||||
|
||||
+13
-14
@@ -1298,16 +1298,15 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
|
||||
return 0;
|
||||
}
|
||||
/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
|
||||
** is disabled, so we might as well hard-code pTab->dbMem to NULL. */
|
||||
** is disabled */
|
||||
assert( db->lookaside.bEnabled==0 );
|
||||
pTab->dbMem = 0;
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = 0;
|
||||
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
||||
selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
|
||||
pTab->iPKey = -1;
|
||||
if( db->mallocFailed ){
|
||||
sqlite3DeleteTable(pTab);
|
||||
sqlite3DeleteTable(db, pTab);
|
||||
return 0;
|
||||
}
|
||||
return pTab;
|
||||
@@ -1799,7 +1798,7 @@ multi_select_end:
|
||||
** regReturn is the number of the register holding the subroutine
|
||||
** return address.
|
||||
**
|
||||
** If regPrev>0 then it is a the first register in a vector that
|
||||
** If regPrev>0 then it is the first register in a vector that
|
||||
** records the previous output. mem[regPrev] is a flag that is false
|
||||
** if there has been no previous output. If regPrev>0 then code is
|
||||
** generated to suppress duplicates. pKeyInfo is used for comparing
|
||||
@@ -2496,12 +2495,13 @@ static void substSelect(
|
||||
** (2) The subquery is not an aggregate or the outer query is not a join.
|
||||
**
|
||||
** (3) The subquery is not the right operand of a left outer join
|
||||
** (Originally ticket #306. Strenghtened by ticket #3300)
|
||||
** (Originally ticket #306. Strengthened by ticket #3300)
|
||||
**
|
||||
** (4) The subquery is not DISTINCT or the outer query is not a join.
|
||||
** (4) The subquery is not DISTINCT.
|
||||
**
|
||||
** (5) The subquery is not DISTINCT or the outer query does not use
|
||||
** aggregates.
|
||||
** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
|
||||
** sub-queries that were excluded from this optimization. Restriction
|
||||
** (4) has since been expanded to exclude all DISTINCT subqueries.
|
||||
**
|
||||
** (6) The subquery does not use aggregates or the outer query is not
|
||||
** DISTINCT.
|
||||
@@ -2521,9 +2521,9 @@ static void substSelect(
|
||||
** (**) Not implemented. Subsumed into restriction (3). Was previously
|
||||
** a separate restriction deriving from ticket #350.
|
||||
**
|
||||
** (13) The subquery and outer query do not both use LIMIT
|
||||
** (13) The subquery and outer query do not both use LIMIT.
|
||||
**
|
||||
** (14) The subquery does not use OFFSET
|
||||
** (14) The subquery does not use OFFSET.
|
||||
**
|
||||
** (15) The outer query is not part of a compound select or the
|
||||
** subquery does not have a LIMIT clause.
|
||||
@@ -2614,9 +2614,9 @@ static int flattenSubquery(
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
if( ((pSub->selFlags & SF_Distinct)!=0 || pSub->pLimit)
|
||||
&& (pSrc->nSrc>1 || isAgg) ){ /* Restrictions (4)(5)(8)(9) */
|
||||
return 0;
|
||||
if( pSub->selFlags & SF_Distinct ) return 0; /* Restriction (5) */
|
||||
if( pSub->pLimit && (pSrc->nSrc>1 || isAgg) ){
|
||||
return 0; /* Restrictions (8)(9) */
|
||||
}
|
||||
if( (p->selFlags & SF_Distinct)!=0 && subqueryIsAgg ){
|
||||
return 0; /* Restriction (6) */
|
||||
@@ -3096,7 +3096,6 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
sqlite3WalkSelect(pWalker, pSel);
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
pTab->dbMem = db->lookaside.bEnabled ? db : 0;
|
||||
pTab->nRef = 1;
|
||||
pTab->zName = sqlite3MPrintf(db, "sqlite_subquery_%p_", (void*)pTab);
|
||||
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
||||
|
||||
+108
-10
@@ -398,6 +398,7 @@ struct previous_mode_data {
|
||||
struct callback_data {
|
||||
sqlite3 *db; /* The database */
|
||||
int echoOn; /* True to echo input commands */
|
||||
int statsOn; /* True to display memory stats before each finalize */
|
||||
int cnt; /* Number of records displayed so far */
|
||||
FILE *out; /* Write results here */
|
||||
int mode; /* An output mode setting */
|
||||
@@ -961,6 +962,86 @@ static char *save_err_msg(
|
||||
return zErrMsg;
|
||||
}
|
||||
|
||||
/*
|
||||
** Display memory stats.
|
||||
*/
|
||||
static int display_stats(
|
||||
sqlite3 *db, /* Database to query */
|
||||
struct callback_data *pArg, /* Pointer to struct callback_data */
|
||||
int bReset /* True to reset the stats */
|
||||
){
|
||||
int iCur;
|
||||
int iHiwtr;
|
||||
|
||||
if( pArg && pArg->out ){
|
||||
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
|
||||
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);
|
||||
/*
|
||||
** Not currently used by the CLI.
|
||||
** iHiwtr = iCur = -1;
|
||||
** sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
** fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr);
|
||||
*/
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
/*
|
||||
** Not currently used by the CLI.
|
||||
** iHiwtr = iCur = -1;
|
||||
** sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
|
||||
** fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr);
|
||||
*/
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr);
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr);
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pArg && pArg->out && db ){
|
||||
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);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
|
||||
}
|
||||
|
||||
if( pArg && pArg->out && db && pArg->pStmt ){
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
|
||||
fprintf(pArg->out, "Fullscan Steps: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
|
||||
fprintf(pArg->out, "Sort Operations: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
|
||||
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute a statement or set of statements. Print
|
||||
** any result rows/columns depending on the current mode
|
||||
@@ -1000,10 +1081,16 @@ static int shell_exec(
|
||||
continue;
|
||||
}
|
||||
|
||||
/* save off the prepared statment handle and reset row count */
|
||||
if( pArg ){
|
||||
pArg->pStmt = pStmt;
|
||||
pArg->cnt = 0;
|
||||
}
|
||||
|
||||
/* echo the sql statement if echo on */
|
||||
if( pArg->echoOn ){
|
||||
if( pArg && pArg->echoOn ){
|
||||
const char *zStmtSql = sqlite3_sql(pStmt);
|
||||
fprintf(pArg->out,"%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
|
||||
}
|
||||
|
||||
/* perform the first step. this will tell us if we
|
||||
@@ -1029,11 +1116,6 @@ static int shell_exec(
|
||||
for(i=0; i<nCol; i++){
|
||||
azCols[i] = (char *)sqlite3_column_name(pStmt, i);
|
||||
}
|
||||
/* save off the prepared statment handle and reset row count */
|
||||
if( pArg ){
|
||||
pArg->pStmt = pStmt;
|
||||
pArg->cnt = 0;
|
||||
}
|
||||
do{
|
||||
/* extract the data and data types */
|
||||
for(i=0; i<nCol; i++){
|
||||
@@ -1056,9 +1138,6 @@ static int shell_exec(
|
||||
}
|
||||
} while( SQLITE_ROW == rc );
|
||||
sqlite3_free(pData);
|
||||
if( pArg ){
|
||||
pArg->pStmt = NULL;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
do{
|
||||
@@ -1067,6 +1146,11 @@ static int shell_exec(
|
||||
}
|
||||
}
|
||||
|
||||
/* print usage stats if stats on */
|
||||
if( pArg && pArg->statsOn ){
|
||||
display_stats(db, pArg, 0);
|
||||
}
|
||||
|
||||
/* Finalize the statement just executed. If this fails, save a
|
||||
** copy of the error message. Otherwise, set zSql to point to the
|
||||
** next statement to execute. */
|
||||
@@ -1077,6 +1161,11 @@ static int shell_exec(
|
||||
}else if( pzErrMsg ){
|
||||
*pzErrMsg = save_err_msg(db);
|
||||
}
|
||||
|
||||
/* clear saved stmt handle */
|
||||
if( pArg ){
|
||||
pArg->pStmt = NULL;
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
@@ -1256,6 +1345,7 @@ static char zHelp[] =
|
||||
" LIKE pattern TABLE.\n"
|
||||
".separator STRING Change separator used by output mode and .import\n"
|
||||
".show Show the current values for various settings\n"
|
||||
".stats ON|OFF Turn stats on or off\n"
|
||||
".tables ?TABLE? List names of tables\n"
|
||||
" If TABLE specified, only list tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
@@ -2001,6 +2091,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
fprintf(p->out,"%9.9s: ", "separator");
|
||||
output_c_string(p->out, p->separator);
|
||||
fprintf(p->out, "\n");
|
||||
fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
|
||||
fprintf(p->out,"%9.9s: ","width");
|
||||
for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
|
||||
fprintf(p->out,"%d ",p->colWidth[i]);
|
||||
@@ -2008,6 +2099,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
fprintf(p->out,"\n");
|
||||
}else
|
||||
|
||||
if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
|
||||
p->statsOn = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
|
||||
char **azResult;
|
||||
int nRow;
|
||||
@@ -2391,6 +2486,7 @@ static const char zOptions[] =
|
||||
" -line set output mode to 'line'\n"
|
||||
" -list set output mode to 'list'\n"
|
||||
" -separator 'x' set output field separator (|)\n"
|
||||
" -stats print memory stats before each finalize\n"
|
||||
" -nullvalue 'text' set text string for NULL values\n"
|
||||
" -version show SQLite version\n"
|
||||
;
|
||||
@@ -2555,6 +2651,8 @@ int main(int argc, char **argv){
|
||||
data.showHeader = 0;
|
||||
}else if( strcmp(z,"-echo")==0 ){
|
||||
data.echoOn = 1;
|
||||
}else if( strcmp(z,"-stats")==0 ){
|
||||
data.statsOn = 1;
|
||||
}else if( strcmp(z,"-bail")==0 ){
|
||||
bail_on_error = 1;
|
||||
}else if( strcmp(z,"-version")==0 ){
|
||||
|
||||
+69
-21
@@ -92,7 +92,7 @@ extern "C" {
|
||||
**
|
||||
** Since version 3.6.18, SQLite source code has been stored in the
|
||||
** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
||||
** system</a>. ^The SQLITE_SOURCE_ID macro evalutes to
|
||||
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
||||
** a string which identifies a particular check-in of SQLite
|
||||
** within its configuration management system. ^The SQLITE_SOURCE_ID
|
||||
** string contains the date and time of the check-in (UTC) and an SHA1
|
||||
@@ -149,7 +149,7 @@ int sqlite3_libversion_number(void);
|
||||
** compile time. ^The SQLITE_ prefix may be omitted from the
|
||||
** option name passed to sqlite3_compileoption_used().
|
||||
**
|
||||
** ^The sqlite3_compileoption_get() function allows interating
|
||||
** ^The sqlite3_compileoption_get() function allows iterating
|
||||
** over the list of options that were defined at compile time by
|
||||
** returning the N-th compile time option string. ^If N is out of range,
|
||||
** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
|
||||
@@ -157,7 +157,7 @@ int sqlite3_libversion_number(void);
|
||||
** sqlite3_compileoption_get().
|
||||
**
|
||||
** ^Support for the diagnostic functions sqlite3_compileoption_used()
|
||||
** and sqlite3_compileoption_get() may be omitted by specifing the
|
||||
** and sqlite3_compileoption_get() may be omitted by specifying the
|
||||
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
|
||||
**
|
||||
** See also: SQL functions [sqlite_compileoption_used()] and
|
||||
@@ -263,7 +263,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
**
|
||||
** ^The sqlite3_close() routine is the destructor for the [sqlite3] object.
|
||||
** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is
|
||||
** successfullly destroyed and all associated resources are deallocated.
|
||||
** successfully destroyed and all associated resources are deallocated.
|
||||
**
|
||||
** Applications must [sqlite3_finalize | finalize] all [prepared statements]
|
||||
** and [sqlite3_blob_close | close] all [BLOB handles] associated with
|
||||
@@ -690,12 +690,21 @@ struct sqlite3_io_methods {
|
||||
** is often close. The underlying VFS might choose to preallocate database
|
||||
** file space based on this hint in order to help writes to the database
|
||||
** file run faster.
|
||||
**
|
||||
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
|
||||
** extends and truncates the database file in chunks of a size specified
|
||||
** by the user. The fourth argument to [sqlite3_file_control()] should
|
||||
** point to an integer (type int) containing the new chunk-size to use
|
||||
** 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.
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
#define SQLITE_SET_LOCKPROXYFILE 3
|
||||
#define SQLITE_LAST_ERRNO 4
|
||||
#define SQLITE_FCNTL_SIZE_HINT 5
|
||||
#define SQLITE_FCNTL_CHUNK_SIZE 6
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -2171,7 +2180,13 @@ int sqlite3_set_authorizer(
|
||||
** ^The callback function registered by sqlite3_profile() is invoked
|
||||
** as each SQL statement finishes. ^The profile callback contains
|
||||
** the original statement text and an estimate of wall-clock time
|
||||
** of how long that statement took to run.
|
||||
** of how long that statement took to run. ^The profile callback
|
||||
** time is in units of nanoseconds, however the current implementation
|
||||
** is only capable of millisecond resolution so the six least significant
|
||||
** digits in the time are meaningless. Future versions of SQLite
|
||||
** might provide greater resolution on the profiler callback. The
|
||||
** sqlite3_profile() function is considered experimental and is
|
||||
** subject to change in future versions of SQLite.
|
||||
*/
|
||||
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||
SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
@@ -2652,7 +2667,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** </ul>
|
||||
**
|
||||
** In the templates above, NNN represents an integer literal,
|
||||
** and VVV represents an alphanumeric identifer.)^ ^The values of these
|
||||
** and VVV represents an alphanumeric identifier.)^ ^The values of these
|
||||
** parameters (also called "host parameter names" or "SQL parameters")
|
||||
** can be set using the sqlite3_bind_*() routines defined here.
|
||||
**
|
||||
@@ -3431,7 +3446,7 @@ int sqlite3_value_numeric_type(sqlite3_value*);
|
||||
/*
|
||||
** CAPI3REF: Obtain Aggregate Function Context
|
||||
**
|
||||
** Implementions of aggregate SQL functions use this
|
||||
** Implementations of aggregate SQL functions use this
|
||||
** routine to allocate memory for storing their state.
|
||||
**
|
||||
** ^The first time the sqlite3_aggregate_context(C,N) routine is called
|
||||
@@ -3703,7 +3718,7 @@ void sqlite3_result_zeroblob(sqlite3_context*, int n);
|
||||
**
|
||||
** A pointer to the user supplied routine must be passed as the fifth
|
||||
** argument. ^If it is NULL, this is the same as deleting the collation
|
||||
** sequence (so that SQLite cannot call it anymore).
|
||||
** sequence (so that SQLite cannot call it any more).
|
||||
** ^Each time the application supplied function is invoked, it is passed
|
||||
** as its first parameter a copy of the void* passed as the fourth argument
|
||||
** to sqlite3_create_collation() or sqlite3_create_collation16().
|
||||
@@ -4320,7 +4335,8 @@ struct sqlite3_module {
|
||||
** CAPI3REF: Virtual Table Indexing Information
|
||||
** KEYWORDS: sqlite3_index_info
|
||||
**
|
||||
** The sqlite3_index_info structure and its substructures is used to
|
||||
** The sqlite3_index_info structure and its substructures is used as part
|
||||
** of the [virtual table] interface to
|
||||
** pass information into and receive the reply from the [xBestIndex]
|
||||
** method of a [virtual table module]. The fields under **Inputs** are the
|
||||
** inputs to xBestIndex and are read-only. xBestIndex inserts its
|
||||
@@ -4328,10 +4344,12 @@ struct sqlite3_module {
|
||||
**
|
||||
** ^(The aConstraint[] array records WHERE clause constraints of the form:
|
||||
**
|
||||
** <pre>column OP expr</pre>
|
||||
** <blockquote>column OP expr</blockquote>
|
||||
**
|
||||
** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is
|
||||
** stored in aConstraint[].op.)^ ^(The index of the column is stored in
|
||||
** stored in aConstraint[].op using one of the
|
||||
** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^
|
||||
** ^(The index of the column is stored in
|
||||
** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the
|
||||
** expr on the right-hand side can be evaluated (and thus the constraint
|
||||
** is usable) and false if it cannot.)^
|
||||
@@ -4391,6 +4409,15 @@ struct sqlite3_index_info {
|
||||
int orderByConsumed; /* True if output is already ordered */
|
||||
double estimatedCost; /* Estimated cost of using this index */
|
||||
};
|
||||
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Constraint Operator Codes
|
||||
**
|
||||
** These macros defined the allowed values for the
|
||||
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
||||
** an operator that is part of a constraint term in the wHERE clause of
|
||||
** a query that uses a [virtual table].
|
||||
*/
|
||||
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
||||
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
||||
#define SQLITE_INDEX_CONSTRAINT_LE 8
|
||||
@@ -4909,7 +4936,7 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
|
||||
** it is passed a NULL pointer).
|
||||
**
|
||||
** The xMutexInit() method must be threadsafe. ^It must be harmless to
|
||||
** invoke xMutexInit() mutiple times within the same process and without
|
||||
** invoke xMutexInit() multiple times within the same process and without
|
||||
** intervening calls to xMutexEnd(). Second and subsequent calls to
|
||||
** xMutexInit() must be no-ops.
|
||||
**
|
||||
@@ -5079,7 +5106,7 @@ int sqlite3_test_control(int op, ...);
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
**
|
||||
** ^This interface is used to retrieve runtime status information
|
||||
** about the preformance of SQLite, and optionally to reset various
|
||||
** about the performance of SQLite, and optionally to reset various
|
||||
** highwater marks. ^The first argument is an integer code for
|
||||
** the specific parameter to measure. ^(Recognized integer codes
|
||||
** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^
|
||||
@@ -5131,6 +5158,9 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** *pHighwater parameter to [sqlite3_status()] is of interest.
|
||||
** 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>)^
|
||||
**
|
||||
** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
||||
** <dd>This parameter returns the number of pages used out of the
|
||||
** [pagecache memory allocator] that was configured using
|
||||
@@ -5192,6 +5222,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
#define SQLITE_STATUS_PARSER_STACK 6
|
||||
#define SQLITE_STATUS_PAGECACHE_SIZE 7
|
||||
#define SQLITE_STATUS_SCRATCH_SIZE 8
|
||||
#define SQLITE_STATUS_MALLOC_COUNT 9
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Status
|
||||
@@ -5201,7 +5232,7 @@ int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
|
||||
** database connection object to be interrogated. ^The second argument
|
||||
** is an integer constant, taken from the set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
|
||||
** determiness the parameter to interrogate. The set of
|
||||
** determines the parameter to interrogate. The set of
|
||||
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
|
||||
** to grow in future releases of SQLite.
|
||||
**
|
||||
@@ -5231,16 +5262,33 @@ 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_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.
|
||||
** ^(<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.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** memory used to store the schema for all databases associated
|
||||
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
||||
** ^The full amount of memory used by the schemas is reported, even if the
|
||||
** schema memory is shared with other database connections due to
|
||||
** [shared cache mode] being enabled.
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
||||
**
|
||||
** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
||||
** and lookaside memory used by all prepared statements associated with
|
||||
** the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
|
||||
#define SQLITE_DBSTATUS_CACHE_USED 1
|
||||
#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
|
||||
#define SQLITE_DBSTATUS_SCHEMA_USED 2
|
||||
#define SQLITE_DBSTATUS_STMT_USED 3
|
||||
#define SQLITE_DBSTATUS_MAX 3 /* Largest defined DBSTATUS */
|
||||
|
||||
|
||||
/*
|
||||
@@ -5606,7 +5654,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
**
|
||||
** ^Each call to sqlite3_backup_step() sets two values inside
|
||||
** the [sqlite3_backup] object: the number of pages still to be backed
|
||||
** up and the total number of pages in the source databae file.
|
||||
** up and the total number of pages in the source database file.
|
||||
** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces
|
||||
** retrieve these two values, respectively.
|
||||
**
|
||||
@@ -5702,7 +5750,7 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
|
||||
** blocked connection already has a registered unlock-notify callback,
|
||||
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
||||
** called with a NULL pointer as its second argument, then any existing
|
||||
** unlock-notify callback is cancelled. ^The blocked connections
|
||||
** unlock-notify callback is canceled. ^The blocked connections
|
||||
** unlock-notify callback may also be canceled by closing the blocked
|
||||
** connection using [sqlite3_close()].
|
||||
**
|
||||
@@ -5784,7 +5832,7 @@ int sqlite3_unlock_notify(
|
||||
**
|
||||
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
|
||||
** compare the contents of two buffers containing UTF-8 strings in a
|
||||
** case-indendent fashion, using the same definition of case independence
|
||||
** case-independent fashion, using the same definition of case independence
|
||||
** that SQLite uses internally when comparing identifiers.
|
||||
*/
|
||||
int sqlite3_strnicmp(const char *, const char *, int);
|
||||
|
||||
+27
-33
@@ -661,14 +661,6 @@ struct Db {
|
||||
|
||||
/*
|
||||
** An instance of the following structure stores a database schema.
|
||||
**
|
||||
** If there are no virtual tables configured in this schema, the
|
||||
** Schema.db variable is set to NULL. After the first virtual table
|
||||
** has been added, it is set to point to the database connection
|
||||
** used to create the connection. Once a virtual table has been
|
||||
** added to the Schema structure and the Schema.db variable populated,
|
||||
** only that database connection may use the Schema to prepare
|
||||
** statements.
|
||||
*/
|
||||
struct Schema {
|
||||
int schema_cookie; /* Database schema version number for this file */
|
||||
@@ -681,9 +673,6 @@ struct Schema {
|
||||
u8 enc; /* Text encoding used by this database */
|
||||
u16 flags; /* Flags associated with this schema */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3 *db; /* "Owner" connection. See comment above */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -871,6 +860,7 @@ struct sqlite3 {
|
||||
int nStatement; /* Number of nested statement-transactions */
|
||||
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
|
||||
i64 nDeferredCons; /* Net deferred constraints this transaction. */
|
||||
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
|
||||
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
/* The following variables are all protected by the STATIC_MASTER
|
||||
@@ -1228,7 +1218,6 @@ struct VTable {
|
||||
** of a SELECT statement.
|
||||
*/
|
||||
struct Table {
|
||||
sqlite3 *dbMem; /* DB connection used for lookaside allocations. */
|
||||
char *zName; /* Name of the table or view */
|
||||
int iPKey; /* If not negative, use aCol[iPKey] as the primary key */
|
||||
int nCol; /* Number of columns in this table */
|
||||
@@ -1365,9 +1354,9 @@ struct FKey {
|
||||
*/
|
||||
struct KeyInfo {
|
||||
sqlite3 *db; /* The database connection */
|
||||
u8 enc; /* Text encoding - one of the TEXT_Utf* values */
|
||||
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
|
||||
u16 nField; /* Number of entries in aColl[] */
|
||||
u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */
|
||||
u8 *aSortOrder; /* Sort order for each column. May be NULL */
|
||||
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
|
||||
};
|
||||
|
||||
@@ -2337,7 +2326,7 @@ struct StrAccum {
|
||||
int nAlloc; /* Amount of space allocated in zText */
|
||||
int mxAlloc; /* Maximum allowed string length */
|
||||
u8 mallocFailed; /* Becomes true if any memory allocation fails */
|
||||
u8 useMalloc; /* True if zText is enlargeable using realloc */
|
||||
u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
|
||||
u8 tooBig; /* Becomes true if string size exceeds limits */
|
||||
};
|
||||
|
||||
@@ -2635,7 +2624,7 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
|
||||
#endif
|
||||
|
||||
void sqlite3DropTable(Parse*, SrcList*, int, int);
|
||||
void sqlite3DeleteTable(Table*);
|
||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
||||
void sqlite3AutoincrementBegin(Parse *pParse);
|
||||
void sqlite3AutoincrementEnd(Parse *pParse);
|
||||
@@ -2869,7 +2858,8 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
|
||||
Expr *sqlite3ExprSetColl(Expr*, CollSeq*);
|
||||
Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
int sqlite3CheckObjectName(Parse *, const char *);
|
||||
void sqlite3VdbeSetChanges(sqlite3 *, int);
|
||||
@@ -2919,7 +2909,7 @@ int sqlite3InvokeBusyHandler(BusyHandler*);
|
||||
int sqlite3FindDb(sqlite3*, Token*);
|
||||
int sqlite3FindDbName(sqlite3 *, const char *);
|
||||
int sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||
void sqlite3DeleteIndexSamples(Index*);
|
||||
void sqlite3DeleteIndexSamples(sqlite3*,Index*);
|
||||
void sqlite3DefaultRowEst(Index*);
|
||||
void sqlite3RegisterLikeFunctions(sqlite3*, int);
|
||||
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
|
||||
@@ -2981,7 +2971,7 @@ void sqlite3AutoLoadExtensions(sqlite3*);
|
||||
# define sqlite3VtabUnlock(X)
|
||||
# define sqlite3VtabUnlockList(X)
|
||||
#else
|
||||
void sqlite3VtabClear(Table*);
|
||||
void sqlite3VtabClear(sqlite3 *db, Table*);
|
||||
int sqlite3VtabSync(sqlite3 *db, char **);
|
||||
int sqlite3VtabRollback(sqlite3 *db);
|
||||
int sqlite3VtabCommit(sqlite3 *db);
|
||||
@@ -3034,9 +3024,9 @@ int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
||||
#define sqlite3FkRequired(a,b,c,d) 0
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
void sqlite3FkDelete(Table*);
|
||||
void sqlite3FkDelete(sqlite3 *, Table*);
|
||||
#else
|
||||
#define sqlite3FkDelete(a)
|
||||
#define sqlite3FkDelete(a,b)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3129,17 +3119,18 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
|
||||
** sqlite3MemdebugHasType() returns true if any of the bits in its second
|
||||
** argument match the type set by the previous sqlite3MemdebugSetType().
|
||||
** sqlite3MemdebugHasType() is intended for use inside assert() statements.
|
||||
** For example:
|
||||
**
|
||||
** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
||||
** sqlite3MemdebugNoType() returns true if none of the bits in its second
|
||||
** argument match the type set by the previous sqlite3MemdebugSetType().
|
||||
**
|
||||
** Perhaps the most important point is the difference between MEMTYPE_HEAP
|
||||
** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have
|
||||
** been allocated by lookaside, except the allocation was too large or
|
||||
** lookaside was already full. It is important to verify that allocations
|
||||
** that might have been satisfied by lookaside are not passed back to
|
||||
** non-lookaside free() routines. Asserts such as the example above are
|
||||
** placed on the non-lookaside free() routines to verify this constraint.
|
||||
** and MEMTYPE_LOOKASIDE. If an allocation is MEMTYPE_LOOKASIDE, that means
|
||||
** it might have been allocated by lookaside, except the allocation was
|
||||
** too large or lookaside was already full. It is important to verify
|
||||
** that allocations that might have been satisfied by lookaside are not
|
||||
** passed back to non-lookaside free() routines. Asserts such as the
|
||||
** example above are placed on the non-lookaside free() routines to verify
|
||||
** this constraint.
|
||||
**
|
||||
** All of this is no-op for a production build. It only comes into
|
||||
** play when the SQLITE_MEMDEBUG compile-time option is used.
|
||||
@@ -3147,13 +3138,16 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
void sqlite3MemdebugSetType(void*,u8);
|
||||
int sqlite3MemdebugHasType(void*,u8);
|
||||
int sqlite3MemdebugNoType(void*,u8);
|
||||
#else
|
||||
# define sqlite3MemdebugSetType(X,Y) /* no-op */
|
||||
# define sqlite3MemdebugHasType(X,Y) 1
|
||||
# define sqlite3MemdebugNoType(X,Y) 1
|
||||
#endif
|
||||
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
|
||||
#define MEMTYPE_DB 0x02 /* Associated with a database connection */
|
||||
#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
|
||||
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
|
||||
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
|
||||
#define MEMTYPE_LOOKASIDE 0x02 /* Might have been lookaside memory */
|
||||
#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
|
||||
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
|
||||
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
|
||||
|
||||
#endif /* _SQLITEINT_H_ */
|
||||
|
||||
+12
-11
@@ -133,20 +133,21 @@
|
||||
# define SQLITE_MAX_VARIABLE_NUMBER 999
|
||||
#endif
|
||||
|
||||
/* Maximum page size. The upper bound on this value is 32768. This a limit
|
||||
** imposed by the necessity of storing the value in a 2-byte unsigned integer
|
||||
** and the fact that the page size must be a power of 2.
|
||||
/* Maximum page size. The upper bound on this value is 65536. This a limit
|
||||
** imposed by the use of 16-bit offsets within each page.
|
||||
**
|
||||
** If this limit is changed, then the compiled library is technically
|
||||
** incompatible with an SQLite library compiled with a different limit. If
|
||||
** a process operating on a database with a page-size of 65536 bytes
|
||||
** crashes, then an instance of SQLite compiled with the default page-size
|
||||
** limit will not be able to rollback the aborted transaction. This could
|
||||
** lead to database corruption.
|
||||
** Earlier versions of SQLite allowed the user to change this value at
|
||||
** compile time. This is no longer permitted, on the grounds that it creates
|
||||
** a library that is technically incompatible with an SQLite library
|
||||
** compiled with a different limit. If a process operating on a database
|
||||
** with a page-size of 65536 bytes crashes, then an instance of SQLite
|
||||
** compiled with the default page-size limit will not be able to rollback
|
||||
** the aborted transaction. This could lead to database corruption.
|
||||
*/
|
||||
#ifndef SQLITE_MAX_PAGE_SIZE
|
||||
# define SQLITE_MAX_PAGE_SIZE 32768
|
||||
#ifdef SQLITE_MAX_PAGE_SIZE
|
||||
# undef SQLITE_MAX_PAGE_SIZE
|
||||
#endif
|
||||
#define SQLITE_MAX_PAGE_SIZE 65536
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+73
-4
@@ -14,14 +14,15 @@
|
||||
** functionality.
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/*
|
||||
** Variables in which to record status information.
|
||||
*/
|
||||
typedef struct sqlite3StatType sqlite3StatType;
|
||||
static SQLITE_WSD struct sqlite3StatType {
|
||||
int nowValue[9]; /* Current value */
|
||||
int mxValue[9]; /* Maximum value */
|
||||
int nowValue[10]; /* Current value */
|
||||
int mxValue[10]; /* Maximum value */
|
||||
} sqlite3Stat = { {0,}, {0,} };
|
||||
|
||||
|
||||
@@ -103,6 +104,8 @@ int sqlite3_db_status(
|
||||
int *pHighwater, /* Write high-water mark here */
|
||||
int resetFlag /* Reset high-water mark if true */
|
||||
){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
switch( op ){
|
||||
case SQLITE_DBSTATUS_LOOKASIDE_USED: {
|
||||
*pCurrent = db->lookaside.nOut;
|
||||
@@ -121,6 +124,7 @@ int sqlite3_db_status(
|
||||
case SQLITE_DBSTATUS_CACHE_USED: {
|
||||
int totalUsed = 0;
|
||||
int i;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
@@ -128,13 +132,78 @@ int sqlite3_db_status(
|
||||
totalUsed += sqlite3PagerMemUsed(pPager);
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
*pCurrent = totalUsed;
|
||||
*pHighwater = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** *pCurrent gets an accurate estimate of the amount of memory used
|
||||
** to store the schema for all databases (main, temp, and any ATTACHed
|
||||
** databases. *pHighwater is set to zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_SCHEMA_USED: {
|
||||
int i; /* Used to iterate through schemas */
|
||||
int nByte = 0; /* Used to accumulate return value */
|
||||
|
||||
db->pnBytesFreed = &nByte;
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Schema *pSchema = db->aDb[i].pSchema;
|
||||
if( ALWAYS(pSchema!=0) ){
|
||||
HashElem *p;
|
||||
|
||||
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
|
||||
pSchema->tblHash.count
|
||||
+ pSchema->trigHash.count
|
||||
+ pSchema->idxHash.count
|
||||
+ pSchema->fkeyHash.count
|
||||
);
|
||||
nByte += sqlite3MallocSize(pSchema->tblHash.ht);
|
||||
nByte += sqlite3MallocSize(pSchema->trigHash.ht);
|
||||
nByte += sqlite3MallocSize(pSchema->idxHash.ht);
|
||||
nByte += sqlite3MallocSize(pSchema->fkeyHash.ht);
|
||||
|
||||
for(p=sqliteHashFirst(&pSchema->trigHash); p; p=sqliteHashNext(p)){
|
||||
sqlite3DeleteTrigger(db, (Trigger*)sqliteHashData(p));
|
||||
}
|
||||
for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){
|
||||
sqlite3DeleteTable(db, (Table *)sqliteHashData(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
db->pnBytesFreed = 0;
|
||||
|
||||
*pHighwater = 0;
|
||||
*pCurrent = nByte;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** *pCurrent gets an accurate estimate of the amount of memory used
|
||||
** to store all prepared statements.
|
||||
** *pHighwater is set to zero.
|
||||
*/
|
||||
case SQLITE_DBSTATUS_STMT_USED: {
|
||||
struct Vdbe *pVdbe; /* Used to iterate through VMs */
|
||||
int nByte = 0; /* Used to accumulate return value */
|
||||
|
||||
db->pnBytesFreed = &nByte;
|
||||
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
|
||||
sqlite3VdbeDeleteObject(db, pVdbe);
|
||||
}
|
||||
db->pnBytesFreed = 0;
|
||||
|
||||
*pHighwater = 0;
|
||||
*pCurrent = nByte;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return SQLITE_ERROR;
|
||||
rc = SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+17
-17
@@ -2571,7 +2571,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
int v;
|
||||
const char *zOp;
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "(step|sort)");
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "(step|sort|autoindex)");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zOp = Tcl_GetString(objv[2]);
|
||||
@@ -3015,7 +3015,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** used to open a new SQLite database. See the DbMain() routine above
|
||||
** for additional information.
|
||||
*/
|
||||
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
|
||||
int Sqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.4", 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
|
||||
@@ -3023,24 +3023,24 @@ EXTERN int Sqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
|
||||
return TCL_OK;
|
||||
}
|
||||
EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
|
||||
int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Sqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Tclsqlite3_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Sqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Tclsqlite3_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
|
||||
|
||||
|
||||
#ifndef SQLITE_3_SUFFIX_ONLY
|
||||
EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
|
||||
int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
int Sqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; }
|
||||
int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;}
|
||||
#endif
|
||||
|
||||
#ifdef TCLSH
|
||||
|
||||
+81
@@ -4613,6 +4613,44 @@ static int file_control_lasterrno_test(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
|
||||
**
|
||||
** This TCL command runs the sqlite3_file_control interface and
|
||||
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
|
||||
** SQLITE_SET_LOCKPROXYFILE verbs.
|
||||
*/
|
||||
static int file_control_chunksize_test(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int nSize; /* New chunk size */
|
||||
char *zDb; /* Db name ("main", "temp" etc.) */
|
||||
sqlite3 *db; /* Database handle */
|
||||
int rc; /* file_control() return code */
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|
||||
|| Tcl_GetIntFromObj(interp, objv[3], &nSize)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
if( zDb[0]=='\0' ) zDb = NULL;
|
||||
|
||||
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize);
|
||||
if( rc ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_lockproxy_test DB PWD
|
||||
**
|
||||
@@ -4911,6 +4949,47 @@ static int test_wal_checkpoint(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: test_sqlite3_log ?SCRIPT?
|
||||
*/
|
||||
static struct LogCallback {
|
||||
Tcl_Interp *pInterp;
|
||||
Tcl_Obj *pObj;
|
||||
} logcallback = {0, 0};
|
||||
static void xLogcallback(void *unused, int err, char *zMsg){
|
||||
Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj);
|
||||
Tcl_IncrRefCount(pNew);
|
||||
Tcl_ListObjAppendElement(
|
||||
0, pNew, Tcl_NewStringObj(sqlite3TestErrorName(err), -1)
|
||||
);
|
||||
Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1));
|
||||
Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
|
||||
Tcl_DecrRefCount(pNew);
|
||||
}
|
||||
static int test_sqlite3_log(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
if( objc>2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SCRIPT");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( logcallback.pObj ){
|
||||
Tcl_DecrRefCount(logcallback.pObj);
|
||||
logcallback.pObj = 0;
|
||||
logcallback.pInterp = 0;
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, 0, 0);
|
||||
}
|
||||
if( objc>1 ){
|
||||
logcallback.pObj = objv[1];
|
||||
Tcl_IncrRefCount(logcallback.pObj);
|
||||
logcallback.pInterp = interp;
|
||||
sqlite3_config(SQLITE_CONFIG_LOG, xLogcallback, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tcl_objproc COMMANDNAME ARGS...
|
||||
@@ -5106,6 +5185,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_test", file_control_test, 0 },
|
||||
{ "file_control_lasterrno_test", file_control_lasterrno_test, 0 },
|
||||
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
|
||||
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
|
||||
/* Functions from os.h */
|
||||
@@ -5133,6 +5213,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
|
||||
#endif
|
||||
{ "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 },
|
||||
{ "test_sqlite3_log", test_sqlite3_log, 0 },
|
||||
};
|
||||
static int bitmask_size = sizeof(Bitmask)*8;
|
||||
int i;
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ static int pager_open(
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
u16 pageSize;
|
||||
u32 pageSize;
|
||||
Pager *pPager;
|
||||
int nPage;
|
||||
int rc;
|
||||
|
||||
+2
-2
@@ -142,7 +142,7 @@ static int tcl_thread_create(
|
||||
}
|
||||
threadset[i].busy = 1;
|
||||
sqlite3_free(threadset[i].zFilename);
|
||||
threadset[i].zFilename = sqlite3DbStrDup(0, argv[2]);
|
||||
threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]);
|
||||
threadset[i].opnum = 1;
|
||||
threadset[i].completed = 0;
|
||||
rc = pthread_create(&x, 0, thread_main, &threadset[i]);
|
||||
@@ -476,7 +476,7 @@ static int tcl_thread_compile(
|
||||
thread_wait(&threadset[i]);
|
||||
threadset[i].xOp = do_compile;
|
||||
sqlite3_free(threadset[i].zArg);
|
||||
threadset[i].zArg = sqlite3DbStrDup(0, argv[2]);
|
||||
threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
|
||||
threadset[i].opnum++;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ static int test_translate(
|
||||
if( enc_from==SQLITE_UTF8 ){
|
||||
z = Tcl_GetString(objv[1]);
|
||||
if( objc==5 ){
|
||||
z = sqlite3DbStrDup(0, z);
|
||||
z = sqlite3_mprintf("%s", z);
|
||||
}
|
||||
sqlite3ValueSetStr(pVal, -1, z, enc_from, xDel);
|
||||
}else{
|
||||
|
||||
+2
-2
@@ -164,7 +164,7 @@ static int tcl_client_create(
|
||||
}
|
||||
threadset[i].busy = 1;
|
||||
sqlite3_free(threadset[i].zFilename);
|
||||
threadset[i].zFilename = sqlite3DbStrDup(0, argv[2]);
|
||||
threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]);
|
||||
threadset[i].opnum = 1;
|
||||
threadset[i].completed = 0;
|
||||
rc = pthread_create(&x, 0, client_main, &threadset[i]);
|
||||
@@ -507,7 +507,7 @@ static int tcl_client_compile(
|
||||
client_wait(&threadset[i]);
|
||||
threadset[i].xOp = do_compile;
|
||||
sqlite3_free(threadset[i].zArg);
|
||||
threadset[i].zArg = sqlite3DbStrDup(0, argv[2]);
|
||||
threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
|
||||
threadset[i].opnum++;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+1
-1
@@ -485,7 +485,7 @@ static int echoCreate(
|
||||
rc = sqlite3_exec(db, zSql, 0, 0, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pzErr = sqlite3DbStrDup(0, sqlite3_errmsg(db));
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-7
@@ -127,6 +127,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
** Size of the write buffer used by journal files in bytes.
|
||||
@@ -135,6 +136,11 @@
|
||||
# define SQLITE_DEMOVFS_BUFFERSZ 8192
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The maximum pathname length supported by this VFS.
|
||||
*/
|
||||
#define MAXPATHNAME 512
|
||||
|
||||
/*
|
||||
** When using this VFS, the sqlite3_file* handles that SQLite uses are
|
||||
** actually pointers to instances of type DemoFile.
|
||||
@@ -446,16 +452,19 @@ static int demoOpen(
|
||||
** file has been synced to disk before returning.
|
||||
*/
|
||||
static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
int rc;
|
||||
int rc; /* Return code */
|
||||
|
||||
rc = unlink(zPath);
|
||||
if( rc!=0 && errno==ENOENT ) return SQLITE_OK;
|
||||
|
||||
if( rc==0 && dirSync ){
|
||||
int dfd; /* File descriptor open on directory */
|
||||
int i; /* Iterator variable */
|
||||
char zDir[pVfs->mxPathname+1];/* Name of directory containing file zPath */
|
||||
char zDir[MAXPATHNAME+1]; /* Name of directory containing file zPath */
|
||||
|
||||
/* Figure out the directory name from the path of the file deleted. */
|
||||
sqlite3_snprintf(pVfs->mxPathname, zDir, "%s", zPath);
|
||||
zDir[pVfs->mxPathname] = '\0';
|
||||
sqlite3_snprintf(MAXPATHNAME, zDir, "%s", zPath);
|
||||
zDir[MAXPATHNAME] = '\0';
|
||||
for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
|
||||
zDir[i] = '\0';
|
||||
|
||||
@@ -524,13 +533,13 @@ static int demoFullPathname(
|
||||
int nPathOut, /* Size of output buffer in bytes */
|
||||
char *zPathOut /* Pointer to output buffer */
|
||||
){
|
||||
char zDir[pVfs->mxPathname+1];
|
||||
char zDir[MAXPATHNAME+1];
|
||||
if( zPath[0]=='/' ){
|
||||
zDir[0] = '\0';
|
||||
}else{
|
||||
getcwd(zDir, sizeof(zDir));
|
||||
}
|
||||
zDir[pVfs->mxPathname] = '\0';
|
||||
zDir[MAXPATHNAME] = '\0';
|
||||
|
||||
sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath);
|
||||
zPathOut[nPathOut-1] = '\0';
|
||||
@@ -609,7 +618,7 @@ sqlite3_vfs *sqlite3_demovfs(void){
|
||||
static sqlite3_vfs demovfs = {
|
||||
1, /* iVersion */
|
||||
sizeof(DemoFile), /* szOsFile */
|
||||
512, /* mxPathname */
|
||||
MAXPATHNAME, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"demo", /* zName */
|
||||
0, /* pAppData */
|
||||
|
||||
+10
-1
@@ -361,6 +361,7 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
|
||||
sqlite3_file *p = pMain->pReal;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
closeTransaction(pMain);
|
||||
aData = sqlite3_malloc(pMain->nPagesize);
|
||||
pMain->pWritable = sqlite3BitvecCreate(pMain->nPage);
|
||||
pMain->aCksum = sqlite3_malloc(sizeof(u32) * (pMain->nPage + 1));
|
||||
@@ -379,6 +380,15 @@ static int openTransaction(jt_file *pMain, jt_file *pJournal){
|
||||
** leaf to the jt_file.pWritable bitvec.
|
||||
*/
|
||||
rc = sqlite3OsRead(p, aData, pMain->nPagesize, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 nDbsize = decodeUint32(&aData[28]);
|
||||
if( nDbsize>0 && memcmp(&aData[24], &aData[92], 4)==0 ){
|
||||
u32 iPg;
|
||||
for(iPg=nDbsize+1; iPg<=pMain->nPage; iPg++){
|
||||
sqlite3BitvecSet(pMain->pWritable, iPg);
|
||||
}
|
||||
}
|
||||
}
|
||||
iTrunk = decodeUint32(&aData[32]);
|
||||
while( rc==SQLITE_OK && iTrunk>0 ){
|
||||
u32 nLeaf;
|
||||
@@ -492,7 +502,6 @@ finish_rjf:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Write data to an jt-file.
|
||||
*/
|
||||
|
||||
+14
-8
@@ -728,7 +728,10 @@ static int test_memdebug_settitle(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
#define MALLOC_LOG_FRAMES 10
|
||||
#define MALLOC_LOG_FRAMES 10
|
||||
#define MALLOC_LOG_KEYINTS ( \
|
||||
10 * ((sizeof(int)>=sizeof(void*)) ? 1 : sizeof(void*)/sizeof(int)) \
|
||||
)
|
||||
static Tcl_HashTable aMallocLog;
|
||||
static int mallocLogEnabled = 0;
|
||||
|
||||
@@ -745,8 +748,8 @@ static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
|
||||
Tcl_HashEntry *pEntry;
|
||||
int isNew;
|
||||
|
||||
int aKey[MALLOC_LOG_FRAMES];
|
||||
int nKey = sizeof(int)*MALLOC_LOG_FRAMES;
|
||||
int aKey[MALLOC_LOG_KEYINTS];
|
||||
int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
|
||||
|
||||
memset(aKey, 0, nKey);
|
||||
if( (sizeof(void*)*nFrame)<nKey ){
|
||||
@@ -781,7 +784,7 @@ static void test_memdebug_log_clear(void){
|
||||
Tcl_Free((char *)pLog);
|
||||
}
|
||||
Tcl_DeleteHashTable(&aMallocLog);
|
||||
Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
|
||||
Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
|
||||
}
|
||||
|
||||
static int test_memdebug_log(
|
||||
@@ -804,7 +807,7 @@ static int test_memdebug_log(
|
||||
void (*xBacktrace)(int, int, void **));
|
||||
sqlite3MemdebugBacktraceCallback(test_memdebug_callback);
|
||||
#endif
|
||||
Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_FRAMES);
|
||||
Tcl_InitHashTable(&aMallocLog, MALLOC_LOG_KEYINTS);
|
||||
isInit = 1;
|
||||
}
|
||||
|
||||
@@ -827,7 +830,7 @@ static int test_memdebug_log(
|
||||
Tcl_HashEntry *pEntry;
|
||||
Tcl_Obj *pRet = Tcl_NewObj();
|
||||
|
||||
assert(sizeof(int)==sizeof(void*));
|
||||
assert(sizeof(Tcl_WideInt)>=sizeof(void*));
|
||||
|
||||
for(
|
||||
pEntry=Tcl_FirstHashEntry(&aMallocLog, &search);
|
||||
@@ -836,13 +839,13 @@ static int test_memdebug_log(
|
||||
){
|
||||
Tcl_Obj *apElem[MALLOC_LOG_FRAMES+2];
|
||||
MallocLog *pLog = (MallocLog *)Tcl_GetHashValue(pEntry);
|
||||
int *aKey = (int *)Tcl_GetHashKey(&aMallocLog, pEntry);
|
||||
Tcl_WideInt *aKey = (Tcl_WideInt *)Tcl_GetHashKey(&aMallocLog, pEntry);
|
||||
int ii;
|
||||
|
||||
apElem[0] = Tcl_NewIntObj(pLog->nCall);
|
||||
apElem[1] = Tcl_NewIntObj(pLog->nByte);
|
||||
for(ii=0; ii<MALLOC_LOG_FRAMES; ii++){
|
||||
apElem[ii+2] = Tcl_NewIntObj(aKey[ii]);
|
||||
apElem[ii+2] = Tcl_NewWideIntObj(aKey[ii]);
|
||||
}
|
||||
|
||||
Tcl_ListObjAppendElement(interp, pRet,
|
||||
@@ -1237,6 +1240,7 @@ static int test_status(
|
||||
{ "SQLITE_STATUS_SCRATCH_OVERFLOW", SQLITE_STATUS_SCRATCH_OVERFLOW },
|
||||
{ "SQLITE_STATUS_SCRATCH_SIZE", SQLITE_STATUS_SCRATCH_SIZE },
|
||||
{ "SQLITE_STATUS_PARSER_STACK", SQLITE_STATUS_PARSER_STACK },
|
||||
{ "SQLITE_STATUS_MALLOC_COUNT", SQLITE_STATUS_MALLOC_COUNT },
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=3 ){
|
||||
@@ -1288,6 +1292,8 @@ static int test_db_status(
|
||||
} 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 }
|
||||
};
|
||||
Tcl_Obj *pResult;
|
||||
if( objc!=4 ){
|
||||
|
||||
+7
-9
@@ -376,7 +376,13 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
||||
if( pCsr->aPage[0].pPg==0 ){
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
int nPage;
|
||||
u32 iRoot = sqlite3_column_int64(pCsr->pStmt, 1);
|
||||
sqlite3PagerPagecount(pPager, &nPage);
|
||||
if( nPage==0 ){
|
||||
pCsr->isEof = 1;
|
||||
return sqlite3_reset(pCsr->pStmt);
|
||||
}
|
||||
rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg);
|
||||
pCsr->aPage[0].iPgno = iRoot;
|
||||
pCsr->aPage[0].iCell = 0;
|
||||
@@ -486,17 +492,9 @@ static int statFilter(
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
sqlite3 *db = ((StatTable *)(pCursor->pVtab))->db;
|
||||
StatCursor *pCsr = (StatCursor *)pCursor;
|
||||
int nPage = 0;
|
||||
|
||||
statResetCsr((StatCursor *)pCursor);
|
||||
sqlite3PagerPagecount(sqlite3BtreePager(db->aDb[0].pBt), &nPage);
|
||||
if( nPage==0 ){
|
||||
pCsr->isEof = 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
statResetCsr(pCsr);
|
||||
return statNext(pCursor);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1000,7 +1000,7 @@ static int testvfs_obj_cmd(
|
||||
int n;
|
||||
u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
|
||||
int pgsz = pBuffer->pgsz;
|
||||
if( pgsz==0 ) pgsz = 32768;
|
||||
if( pgsz==0 ) pgsz = 65536;
|
||||
for(i=0; i*pgsz<n; i++){
|
||||
int nByte = pgsz;
|
||||
tvfsAllocPage(pBuffer, i, pgsz);
|
||||
@@ -1014,7 +1014,7 @@ static int testvfs_obj_cmd(
|
||||
pObj = Tcl_NewObj();
|
||||
for(i=0; pBuffer->aPage[i]; i++){
|
||||
int pgsz = pBuffer->pgsz;
|
||||
if( pgsz==0 ) pgsz = 32768;
|
||||
if( pgsz==0 ) pgsz = 65536;
|
||||
Tcl_AppendObjToObj(pObj, Tcl_NewByteArrayObj(pBuffer->aPage[i], pgsz));
|
||||
}
|
||||
Tcl_SetObjResult(interp, pObj);
|
||||
|
||||
+3
-3
@@ -496,7 +496,7 @@ abort_parse:
|
||||
}
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
sqlite3DbFree(db, pParse->apVtabLock);
|
||||
sqlite3_free(pParse->apVtabLock);
|
||||
#endif
|
||||
|
||||
if( !IN_DECLARE_VTAB ){
|
||||
@@ -504,7 +504,7 @@ abort_parse:
|
||||
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
||||
** will take responsibility for freeing the Table structure.
|
||||
*/
|
||||
sqlite3DeleteTable(pParse->pNewTable);
|
||||
sqlite3DeleteTable(db, pParse->pNewTable);
|
||||
}
|
||||
|
||||
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
||||
@@ -518,7 +518,7 @@ abort_parse:
|
||||
while( pParse->pZombieTab ){
|
||||
Table *p = pParse->pZombieTab;
|
||||
pParse->pZombieTab = p->pNextZombie;
|
||||
sqlite3DeleteTable(p);
|
||||
sqlite3DeleteTable(db, p);
|
||||
}
|
||||
if( nErr>0 && pParse->rc==SQLITE_OK ){
|
||||
pParse->rc = SQLITE_ERROR;
|
||||
|
||||
+5
-3
@@ -800,6 +800,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
||||
|
||||
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
||||
assert( pTop->pVdbe );
|
||||
|
||||
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
|
||||
** are freed if an error occurs, link them into the Parse.pTriggerPrg
|
||||
@@ -810,7 +811,7 @@ static TriggerPrg *codeRowTrigger(
|
||||
pTop->pTriggerPrg = pPrg;
|
||||
pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram));
|
||||
if( !pProgram ) return 0;
|
||||
pProgram->nRef = 1;
|
||||
sqlite3VdbeLinkSubProgram(pTop->pVdbe, pProgram);
|
||||
pPrg->pTrigger = pTrigger;
|
||||
pPrg->orconf = orconf;
|
||||
pPrg->aColmask[0] = 0xffffffff;
|
||||
@@ -944,8 +945,9 @@ void sqlite3CodeRowTriggerDirect(
|
||||
/* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
||||
** is a pointer to the sub-vdbe containing the trigger program. */
|
||||
if( pPrg ){
|
||||
int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
|
||||
pPrg->pProgram->nRef++;
|
||||
sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
|
||||
VdbeComment(
|
||||
(v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf)));
|
||||
@@ -955,7 +957,7 @@ void sqlite3CodeRowTriggerDirect(
|
||||
** invocation is disallowed if (a) the sub-program is really a trigger,
|
||||
** not a foreign key action, and (b) the flag to enable recursive triggers
|
||||
** is clear. */
|
||||
sqlite3VdbeChangeP5(v, (u8)(p->zName && !(pParse->db->flags&SQLITE_RecTriggers)));
|
||||
sqlite3VdbeChangeP5(v, (u8)bRecursive);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
sqlite*************************************************************************
|
||||
*************************************************************************
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
*/
|
||||
|
||||
+23
-27
@@ -501,6 +501,20 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
|
||||
** in memory obtained from sqlite3DbMalloc).
|
||||
*/
|
||||
static void importVtabErrMsg(Vdbe *p, sqlite3_vtab *pVtab){
|
||||
sqlite3 *db = p->db;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
pVtab->zErrMsg = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can then return.
|
||||
**
|
||||
@@ -4030,9 +4044,7 @@ case OP_Rowid: { /* out2-prerelease */
|
||||
pModule = pVtab->pModule;
|
||||
assert( pModule->xRowid );
|
||||
rc = pModule->xRowid(pC->pVtabCursor, &v);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}else{
|
||||
assert( pC->pCursor!=0 );
|
||||
@@ -4337,7 +4349,7 @@ case OP_IdxRowid: { /* out2-prerelease */
|
||||
** that if the key from register P3 is a prefix of the key in the cursor,
|
||||
** the result is false whereas it would be true with IdxGT.
|
||||
*/
|
||||
/* Opcode: IdxLT P1 P2 P3 * P5
|
||||
/* Opcode: IdxLT P1 P2 P3 P4 P5
|
||||
**
|
||||
** The P4 register values beginning with P3 form an unpacked index
|
||||
** key that omits the ROWID. Compare this key value against the index
|
||||
@@ -5375,11 +5387,7 @@ case OP_VBegin: {
|
||||
VTable *pVTab;
|
||||
pVTab = pOp->p4.pVtab;
|
||||
rc = sqlite3VtabBegin(db, pVTab);
|
||||
if( pVTab ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVTab->pVtab->zErrMsg;
|
||||
pVTab->pVtab->zErrMsg = 0;
|
||||
}
|
||||
if( pVTab ) importVtabErrMsg(p, pVTab->pVtab);
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
@@ -5429,9 +5437,7 @@ case OP_VOpen: {
|
||||
pModule = (sqlite3_module *)pVtab->pModule;
|
||||
assert(pVtab && pModule);
|
||||
rc = pModule->xOpen(pVtab, &pVtabCursor);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( SQLITE_OK==rc ){
|
||||
/* Initialize sqlite3_vtab_cursor base class */
|
||||
pVtabCursor->pVtab = pVtab;
|
||||
@@ -5508,9 +5514,7 @@ case OP_VFilter: { /* jump */
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
|
||||
p->inVtabMethod = 0;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pVtabCursor);
|
||||
}
|
||||
@@ -5560,9 +5564,7 @@ case OP_VColumn: {
|
||||
MemSetTypeFlag(&sContext.s, MEM_Null);
|
||||
|
||||
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( sContext.isError ){
|
||||
rc = sContext.isError;
|
||||
}
|
||||
@@ -5615,9 +5617,7 @@ case OP_VNext: { /* jump */
|
||||
p->inVtabMethod = 1;
|
||||
rc = pModule->xNext(pCur->pVtabCursor);
|
||||
p->inVtabMethod = 0;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( rc==SQLITE_OK ){
|
||||
res = pModule->xEof(pCur->pVtabCursor);
|
||||
}
|
||||
@@ -5647,9 +5647,7 @@ case OP_VRename: {
|
||||
REGISTER_TRACE(pOp->p1, pName);
|
||||
assert( pName->flags & MEM_Str );
|
||||
rc = pVtab->pModule->xRename(pVtab, pName->z);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -5701,9 +5699,7 @@ case OP_VUpdate: {
|
||||
pX++;
|
||||
}
|
||||
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
importVtabErrMsg(p, pVtab);
|
||||
if( rc==SQLITE_OK && pOp->p1 ){
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = rowid;
|
||||
|
||||
+6
-2
@@ -81,8 +81,8 @@ struct SubProgram {
|
||||
int nOp; /* Elements in aOp[] */
|
||||
int nMem; /* Number of memory cells required */
|
||||
int nCsr; /* Number of cursors required */
|
||||
int nRef; /* Number of pointers to this structure */
|
||||
void *token; /* id that may be used to recursive triggers */
|
||||
SubProgram *pNext; /* Next sub-program already visited */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -184,6 +184,7 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
||||
void sqlite3VdbeDelete(Vdbe*);
|
||||
void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*);
|
||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int);
|
||||
int sqlite3VdbeFinalize(Vdbe*);
|
||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||
@@ -201,7 +202,6 @@ sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
|
||||
void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int);
|
||||
sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
|
||||
void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
@@ -212,6 +212,10 @@ UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int);
|
||||
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeComment(Vdbe*, const char*, ...);
|
||||
|
||||
@@ -323,6 +323,7 @@ struct Vdbe {
|
||||
VdbeFrame *pFrame; /* Parent frame */
|
||||
int nFrame; /* Number of frames in pFrame list */
|
||||
u32 expmask; /* Binding to these vars invalidates VM */
|
||||
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -398,7 +398,7 @@ static int sqlite3Step(Vdbe *p){
|
||||
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
|
||||
sqlite3_int64 iNow;
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
|
||||
db->xProfile(db->pProfileArg, p->zSql, iNow - p->startTime);
|
||||
db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+73
-54
@@ -573,15 +573,17 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
||||
}
|
||||
}
|
||||
|
||||
static void vdbeFreeOpArray(sqlite3 *, Op *, int);
|
||||
|
||||
/*
|
||||
** Delete a P4 value if necessary.
|
||||
*/
|
||||
static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
if( p4 ){
|
||||
assert( db );
|
||||
switch( p4type ){
|
||||
case P4_REAL:
|
||||
case P4_INT64:
|
||||
case P4_MPRINTF:
|
||||
case P4_DYNAMIC:
|
||||
case P4_KEYINFO:
|
||||
case P4_INTARRAY:
|
||||
@@ -589,10 +591,14 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
sqlite3DbFree(db, p4);
|
||||
break;
|
||||
}
|
||||
case P4_MPRINTF: {
|
||||
if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
||||
break;
|
||||
}
|
||||
case P4_VDBEFUNC: {
|
||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
|
||||
freeEphemeralFunction(db, pVdbeFunc->pFunc);
|
||||
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
sqlite3DbFree(db, pVdbeFunc);
|
||||
break;
|
||||
}
|
||||
@@ -601,15 +607,17 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
break;
|
||||
}
|
||||
case P4_MEM: {
|
||||
sqlite3ValueFree((sqlite3_value*)p4);
|
||||
if( db->pnBytesFreed==0 ){
|
||||
sqlite3ValueFree((sqlite3_value*)p4);
|
||||
}else{
|
||||
Mem *p = (Mem*)p4;
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P4_VTAB : {
|
||||
sqlite3VtabUnlock((VTable *)p4);
|
||||
break;
|
||||
}
|
||||
case P4_SUBPROGRAM : {
|
||||
sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1);
|
||||
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -635,35 +643,15 @@ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
||||
}
|
||||
|
||||
/*
|
||||
** Decrement the ref-count on the SubProgram structure passed as the
|
||||
** second argument. If the ref-count reaches zero, free the structure.
|
||||
**
|
||||
** The array of VDBE opcodes stored as SubProgram.aOp is freed if
|
||||
** either the ref-count reaches zero or parameter freeop is non-zero.
|
||||
**
|
||||
** Since the array of opcodes pointed to by SubProgram.aOp may directly
|
||||
** or indirectly contain a reference to the SubProgram structure itself.
|
||||
** By passing a non-zero freeop parameter, the caller may ensure that all
|
||||
** SubProgram structures and their aOp arrays are freed, even when there
|
||||
** are such circular references.
|
||||
** Link the SubProgram object passed as the second argument into the linked
|
||||
** list at Vdbe.pSubProgram. This list is used to delete all sub-program
|
||||
** objects when the VM is no longer required.
|
||||
*/
|
||||
void sqlite3VdbeProgramDelete(sqlite3 *db, SubProgram *p, int freeop){
|
||||
if( p ){
|
||||
assert( p->nRef>0 );
|
||||
if( freeop || p->nRef==1 ){
|
||||
Op *aOp = p->aOp;
|
||||
p->aOp = 0;
|
||||
vdbeFreeOpArray(db, aOp, p->nOp);
|
||||
p->nOp = 0;
|
||||
}
|
||||
p->nRef--;
|
||||
if( p->nRef==0 ){
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
}
|
||||
void sqlite3VdbeLinkSubProgram(Vdbe *pVdbe, SubProgram *p){
|
||||
p->pNext = pVdbe->pProgram;
|
||||
pVdbe->pProgram = p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change N opcodes starting at addr to No-ops.
|
||||
*/
|
||||
@@ -739,7 +727,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
|
||||
|
||||
nField = ((KeyInfo*)zP4)->nField;
|
||||
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
|
||||
pKeyInfo = sqlite3Malloc( nByte );
|
||||
pKeyInfo = sqlite3DbMallocRaw(0, nByte);
|
||||
pOp->p4.pKeyInfo = pKeyInfo;
|
||||
if( pKeyInfo ){
|
||||
u8 *aSortOrder;
|
||||
@@ -1003,6 +991,12 @@ static void releaseMemArray(Mem *p, int N){
|
||||
Mem *pEnd;
|
||||
sqlite3 *db = p->db;
|
||||
u8 malloc_failed = db->mallocFailed;
|
||||
if( db->pnBytesFreed ){
|
||||
for(pEnd=&p[N]; p<pEnd; p++){
|
||||
sqlite3DbFree(db, p->zMalloc);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for(pEnd=&p[N]; p<pEnd; p++){
|
||||
assert( (&p[1])==pEnd || p[0].db==p[1].db );
|
||||
|
||||
@@ -1652,9 +1646,6 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
** to the transaction.
|
||||
*/
|
||||
rc = sqlite3VtabSync(db, &p->zErrMsg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This loop determines (a) if the commit hook should be invoked and
|
||||
** (b) how many database files have open write transactions, not
|
||||
@@ -1662,13 +1653,17 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
** one database file has an open write transaction, a master journal
|
||||
** file is required for an atomic commit.
|
||||
*/
|
||||
for(i=0; i<db->nDb; i++){
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( sqlite3BtreeIsInTrans(pBt) ){
|
||||
needXcommit = 1;
|
||||
if( i!=1 ) nTrans++;
|
||||
rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* If there are any write-transactions at all, invoke the commit hook */
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
@@ -1807,6 +1802,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
}
|
||||
}
|
||||
sqlite3OsCloseFree(pMaster);
|
||||
assert( rc!=SQLITE_BUSY );
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3DbFree(db, zMaster);
|
||||
return rc;
|
||||
@@ -2065,8 +2061,17 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|
||||
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
|
||||
if( isSpecialError ){
|
||||
/* If the query was read-only, we need do no rollback at all. Otherwise,
|
||||
** proceed with the special handling.
|
||||
/* If the query was read-only and the error code is SQLITE_INTERRUPT,
|
||||
** no rollback is necessary. Otherwise, at least a savepoint
|
||||
** transaction must be rolled back to restore the database to a
|
||||
** consistent state.
|
||||
**
|
||||
** Even if the statement is read-only, it is important to perform
|
||||
** a statement or transaction rollback operation. If the error
|
||||
** occured while writing to the journal, sub-journal or database
|
||||
** file as part of an effort to free up cache space (see function
|
||||
** pagerStress() in pager.c), the rollback is required to restore
|
||||
** the pager to a consistent state.
|
||||
*/
|
||||
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
|
||||
if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){
|
||||
@@ -2335,6 +2340,30 @@ void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all memory associated with the Vdbe passed as the second argument.
|
||||
** The difference between this function and sqlite3VdbeDelete() is that
|
||||
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
|
||||
** the database connection.
|
||||
*/
|
||||
void sqlite3VdbeDeleteObject(sqlite3 *db, Vdbe *p){
|
||||
SubProgram *pSub, *pNext;
|
||||
assert( p->db==0 || p->db==db );
|
||||
releaseMemArray(p->aVar, p->nVar);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
for(pSub=p->pProgram; pSub; pSub=pNext){
|
||||
pNext = pSub->pNext;
|
||||
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
|
||||
sqlite3DbFree(db, pSub);
|
||||
}
|
||||
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
||||
sqlite3DbFree(db, p->aLabel);
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete an entire VDBE.
|
||||
*/
|
||||
@@ -2352,16 +2381,9 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||
if( p->pNext ){
|
||||
p->pNext->pPrev = p->pPrev;
|
||||
}
|
||||
releaseMemArray(p->aVar, p->nVar);
|
||||
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
||||
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
||||
sqlite3DbFree(db, p->aLabel);
|
||||
sqlite3DbFree(db, p->aColName);
|
||||
sqlite3DbFree(db, p->zSql);
|
||||
p->magic = VDBE_MAGIC_DEAD;
|
||||
sqlite3DbFree(db, p->pFree);
|
||||
p->db = 0;
|
||||
sqlite3DbFree(db, p);
|
||||
sqlite3VdbeDeleteObject(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2387,11 +2409,8 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
rc = sqlite3BtreeMovetoUnpacked(p->pCursor, 0, p->movetoTarget, 0, &res);
|
||||
if( rc ) return rc;
|
||||
p->lastRowid = p->movetoTarget;
|
||||
p->rowidIsValid = ALWAYS(res==0) ?1:0;
|
||||
if( NEVER(res<0) ){
|
||||
rc = sqlite3BtreeNext(p->pCursor, &res);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
||||
p->rowidIsValid = 1;
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_search_count++;
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -1016,7 +1016,7 @@ int sqlite3ValueFromExpr(
|
||||
}
|
||||
op = pExpr->op;
|
||||
|
||||
/* op can only be TK_REGISTER is we have compiled with SQLITE_ENABLE_STAT2.
|
||||
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2.
|
||||
** The ifdef here is to enable us to achieve 100% branch test coverage even
|
||||
** when SQLITE_ENABLE_STAT2 is omitted.
|
||||
*/
|
||||
|
||||
+8
-9
@@ -221,14 +221,14 @@ void sqlite3VtabUnlockList(sqlite3 *db){
|
||||
** in the list are moved to the sqlite3.pDisconnect list of the associated
|
||||
** database connection.
|
||||
*/
|
||||
void sqlite3VtabClear(Table *p){
|
||||
vtabDisconnectAll(0, p);
|
||||
void sqlite3VtabClear(sqlite3 *db, Table *p){
|
||||
if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
|
||||
if( p->azModuleArg ){
|
||||
int i;
|
||||
for(i=0; i<p->nModuleArg; i++){
|
||||
sqlite3DbFree(p->dbMem, p->azModuleArg[i]);
|
||||
sqlite3DbFree(db, p->azModuleArg[i]);
|
||||
}
|
||||
sqlite3DbFree(p->dbMem, p->azModuleArg);
|
||||
sqlite3DbFree(db, p->azModuleArg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +393,6 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
|
||||
return;
|
||||
}
|
||||
pSchema->db = pParse->db;
|
||||
pParse->pNewTable = 0;
|
||||
}
|
||||
}
|
||||
@@ -467,7 +466,7 @@ static int vtabCallConstructor(
|
||||
*pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
|
||||
}else {
|
||||
*pzErr = sqlite3MPrintf(db, "%s", zErr);
|
||||
sqlite3DbFree(db, zErr);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
sqlite3DbFree(db, pVTable);
|
||||
}else if( ALWAYS(pVTable->pVtab) ){
|
||||
@@ -682,7 +681,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
||||
if( pParse->pVdbe ){
|
||||
sqlite3VdbeFinalize(pParse->pVdbe);
|
||||
}
|
||||
sqlite3DeleteTable(pParse->pNewTable);
|
||||
sqlite3DeleteTable(db, pParse->pNewTable);
|
||||
sqlite3StackFree(db, pParse);
|
||||
}
|
||||
|
||||
@@ -769,8 +768,8 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
|
||||
rc = x(pVtab);
|
||||
sqlite3DbFree(db, *pzErrmsg);
|
||||
*pzErrmsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
*pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
}
|
||||
}
|
||||
db->aVTrans = aVTrans;
|
||||
|
||||
@@ -292,6 +292,10 @@ typedef struct WalCkptInfo WalCkptInfo;
|
||||
**
|
||||
** The actual header in the wal-index consists of two copies of this
|
||||
** object.
|
||||
**
|
||||
** The szPage value can be any power of 2 between 512 and 32768, inclusive.
|
||||
** Or it can be 1 to represent a 65536-byte page. The latter case was
|
||||
** added in 3.7.1 when support for 64K pages was added.
|
||||
*/
|
||||
struct WalIndexHdr {
|
||||
u32 iVersion; /* Wal-index version */
|
||||
@@ -299,7 +303,7 @@ struct WalIndexHdr {
|
||||
u32 iChange; /* Counter incremented each transaction */
|
||||
u8 isInit; /* 1 when initialized */
|
||||
u8 bigEndCksum; /* True if checksums in WAL are big-endian */
|
||||
u16 szPage; /* Database page size in bytes */
|
||||
u16 szPage; /* Database page size in bytes. 1==64K */
|
||||
u32 mxFrame; /* Index of last valid frame in the WAL */
|
||||
u32 nPage; /* Size of database in pages */
|
||||
u32 aFrameCksum[2]; /* Checksum of last frame in log */
|
||||
@@ -410,7 +414,7 @@ struct Wal {
|
||||
u32 iCallback; /* Value to pass to log callback (or 0) */
|
||||
int nWiData; /* Size of array apWiData */
|
||||
volatile u32 **apWiData; /* Pointer to wal-index content in memory */
|
||||
u16 szPage; /* Database page size */
|
||||
u32 szPage; /* Database page size */
|
||||
i16 readLock; /* Which read lock is being held. -1 for none */
|
||||
u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */
|
||||
u8 writeLock; /* True if in a write transaction */
|
||||
@@ -1081,7 +1085,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
goto finished;
|
||||
}
|
||||
pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
|
||||
pWal->szPage = (u16)szPage;
|
||||
pWal->szPage = szPage;
|
||||
pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
|
||||
memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
|
||||
|
||||
@@ -1131,7 +1135,9 @@ static int walIndexRecover(Wal *pWal){
|
||||
if( nTruncate ){
|
||||
pWal->hdr.mxFrame = iFrame;
|
||||
pWal->hdr.nPage = nTruncate;
|
||||
pWal->hdr.szPage = (u16)szPage;
|
||||
pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
|
||||
aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
|
||||
}
|
||||
@@ -1156,6 +1162,17 @@ finished:
|
||||
pInfo->nBackfill = 0;
|
||||
pInfo->aReadMark[0] = 0;
|
||||
for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
|
||||
/* If more than one frame was recovered from the log file, report an
|
||||
** event via sqlite3_log(). This is to help with identifying performance
|
||||
** problems caused by applications routinely shutting down without
|
||||
** checkpointing the log file.
|
||||
*/
|
||||
if( pWal->hdr.nPage ){
|
||||
sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
|
||||
pWal->hdr.nPage, pWal->zWalName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
recovery_error:
|
||||
@@ -1516,14 +1533,18 @@ static int walCheckpoint(
|
||||
u8 *zBuf /* Temporary buffer to use */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int szPage = pWal->hdr.szPage; /* Database page-size */
|
||||
int szPage; /* Database page-size */
|
||||
WalIterator *pIter = 0; /* Wal iterator context */
|
||||
u32 iDbpage = 0; /* Next database page to write */
|
||||
u32 iFrame = 0; /* Wal frame containing data for iDbpage */
|
||||
u32 mxSafeFrame; /* Max frame that can be backfilled */
|
||||
u32 mxPage; /* Max database page to write */
|
||||
int i; /* Loop counter */
|
||||
volatile WalCkptInfo *pInfo; /* The checkpoint status information */
|
||||
|
||||
szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
if( pWal->hdr.mxFrame==0 ) return SQLITE_OK;
|
||||
|
||||
/* Allocate the iterator */
|
||||
@@ -1534,7 +1555,7 @@ static int walCheckpoint(
|
||||
assert( pIter );
|
||||
|
||||
/*** TODO: Move this test out to the caller. Make it an assert() here ***/
|
||||
if( pWal->hdr.szPage!=nBuf ){
|
||||
if( szPage!=nBuf ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
@@ -1545,6 +1566,7 @@ static int walCheckpoint(
|
||||
** cannot be backfilled from the WAL.
|
||||
*/
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
pInfo = walCkptInfo(pWal);
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
@@ -1565,6 +1587,7 @@ static int walCheckpoint(
|
||||
if( pInfo->nBackfill<mxSafeFrame
|
||||
&& (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK
|
||||
){
|
||||
i64 nSize; /* Current size of database file */
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
|
||||
/* Sync the WAL to disk */
|
||||
@@ -1572,11 +1595,22 @@ static int walCheckpoint(
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* If the database file may grow as a result of this checkpoint, hint
|
||||
** about the eventual size of the db file to the VFS layer.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nReq = ((i64)mxPage * szPage);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file. */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame ) continue;
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
|
||||
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
|
||||
@@ -1683,7 +1717,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||
/* The first page of the wal-index must be mapped at this point. */
|
||||
assert( pWal->nWiData>0 && pWal->apWiData[0] );
|
||||
|
||||
/* Read the header. This might happen currently with a write to the
|
||||
/* Read the header. This might happen concurrently with a write to the
|
||||
** same area of shared memory on a different CPU in a SMP,
|
||||
** meaning it is possible that an inconsistent snapshot is read
|
||||
** from the file. If this happens, return non-zero.
|
||||
@@ -1712,7 +1746,9 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
||||
if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
|
||||
*pChanged = 1;
|
||||
memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
|
||||
pWal->szPage = pWal->hdr.szPage;
|
||||
pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
testcase( pWal->szPage<=32768 );
|
||||
testcase( pWal->szPage>=65536 );
|
||||
}
|
||||
|
||||
/* The header was successfully read. Return zero. */
|
||||
@@ -2031,6 +2067,7 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
** read-lock.
|
||||
*/
|
||||
void sqlite3WalEndReadTransaction(Wal *pWal){
|
||||
sqlite3WalEndWriteTransaction(pWal);
|
||||
if( pWal->readLock>=0 ){
|
||||
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
|
||||
pWal->readLock = -1;
|
||||
@@ -2141,7 +2178,13 @@ int sqlite3WalRead(
|
||||
** required page. Read and return data from the log file.
|
||||
*/
|
||||
if( iRead ){
|
||||
i64 iOffset = walFrameOffset(iRead, pWal->hdr.szPage) + WAL_FRAME_HDRSIZE;
|
||||
int sz;
|
||||
i64 iOffset;
|
||||
sz = pWal->hdr.szPage;
|
||||
sz = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
testcase( sz<=32768 );
|
||||
testcase( sz>=65536 );
|
||||
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
|
||||
*pInWal = 1;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
|
||||
return sqlite3OsRead(pWal->pWalFd, pOut, nOut, iOffset);
|
||||
@@ -2153,11 +2196,13 @@ int sqlite3WalRead(
|
||||
|
||||
|
||||
/*
|
||||
** Set *pPgno to the size of the database file (or zero, if unknown).
|
||||
** Return the size of the database in pages (or zero, if unknown).
|
||||
*/
|
||||
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno){
|
||||
assert( pWal->readLock>=0 || pWal->lockError );
|
||||
*pPgno = pWal->hdr.nPage;
|
||||
Pgno sqlite3WalDbsize(Wal *pWal){
|
||||
if( pWal && ALWAYS(pWal->readLock>=0) ){
|
||||
return pWal->hdr.nPage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -2233,7 +2278,7 @@ int sqlite3WalEndWriteTransaction(Wal *pWal){
|
||||
*/
|
||||
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||
int rc = SQLITE_OK;
|
||||
if( pWal->writeLock ){
|
||||
if( ALWAYS(pWal->writeLock) ){
|
||||
Pgno iMax = pWal->hdr.mxFrame;
|
||||
Pgno iFrame;
|
||||
|
||||
@@ -2422,7 +2467,7 @@ int sqlite3WalFrames(
|
||||
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
|
||||
sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
|
||||
|
||||
pWal->szPage = (u16)szPage;
|
||||
pWal->szPage = szPage;
|
||||
pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
|
||||
pWal->hdr.aFrameCksum[0] = aCksum[0];
|
||||
pWal->hdr.aFrameCksum[1] = aCksum[1];
|
||||
@@ -2517,7 +2562,9 @@ int sqlite3WalFrames(
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
/* Update the private copy of the header. */
|
||||
pWal->hdr.szPage = (u16)szPage;
|
||||
pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
pWal->hdr.mxFrame = iFrame;
|
||||
if( isCommit ){
|
||||
pWal->hdr.iChange++;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# define sqlite3WalBeginReadTransaction(y,z) 0
|
||||
# define sqlite3WalEndReadTransaction(z)
|
||||
# define sqlite3WalRead(v,w,x,y,z) 0
|
||||
# define sqlite3WalDbsize(y,z)
|
||||
# define sqlite3WalDbsize(y) 0
|
||||
# define sqlite3WalBeginWriteTransaction(y) 0
|
||||
# define sqlite3WalEndWriteTransaction(x) 0
|
||||
# define sqlite3WalUndo(x,y,z) 0
|
||||
@@ -61,9 +61,8 @@ void sqlite3WalEndReadTransaction(Wal *pWal);
|
||||
/* Read a page from the write-ahead log, if it is present. */
|
||||
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
|
||||
|
||||
/* Return the size of the database as it existed at the beginning
|
||||
** of the snapshot */
|
||||
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
|
||||
/* If the WAL is not empty, return the size of the database. */
|
||||
Pgno sqlite3WalDbsize(Wal *pWal);
|
||||
|
||||
/* Obtain or release the WRITER lock. */
|
||||
int sqlite3WalBeginWriteTransaction(Wal *pWal);
|
||||
|
||||
+89
-34
@@ -327,6 +327,7 @@ static void whereClauseClear(WhereClause *pWC){
|
||||
static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
|
||||
WhereTerm *pTerm;
|
||||
int idx;
|
||||
testcase( wtFlags & TERM_VIRTUAL ); /* EV: R-00211-15100 */
|
||||
if( pWC->nTerm>=pWC->nSlot ){
|
||||
WhereTerm *pOld = pWC->a;
|
||||
sqlite3 *db = pWC->pParse->db;
|
||||
@@ -472,6 +473,13 @@ static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){
|
||||
** Return TRUE if the given operator is one of the operators that is
|
||||
** allowed for an indexable WHERE clause term. The allowed operators are
|
||||
** "=", "<", ">", "<=", ">=", and "IN".
|
||||
**
|
||||
** IMPLEMENTATION-OF: R-59926-26393 To be usable by an index a term must be
|
||||
** of one of the following forms: column = expression column > expression
|
||||
** column >= expression column < expression column <= expression
|
||||
** expression = column expression > column expression >= column
|
||||
** expression < column expression <= column column IN
|
||||
** (expression-list) column IN (subquery) column IS NULL
|
||||
*/
|
||||
static int allowedOp(int op){
|
||||
assert( TK_GT>TK_EQ && TK_GT<TK_GE );
|
||||
@@ -635,7 +643,6 @@ static int isLikeOrGlob(
|
||||
int c; /* One character in z[] */
|
||||
int cnt; /* Number of non-wildcard prefix characters */
|
||||
char wc[3]; /* Wildcard characters */
|
||||
CollSeq *pColl; /* Collating sequence for LHS */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
sqlite3_value *pVal = 0;
|
||||
int op; /* Opcode of pRight */
|
||||
@@ -654,19 +661,6 @@ static int isLikeOrGlob(
|
||||
return 0;
|
||||
}
|
||||
assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */
|
||||
pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
if( pColl==0 ) return 0; /* Happens when LHS has an undefined collation */
|
||||
if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) &&
|
||||
(pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){
|
||||
/* IMP: R-09003-32046 For the GLOB operator, the column must use the
|
||||
** default BINARY collating sequence.
|
||||
** IMP: R-41408-28306 For the LIKE operator, if case_sensitive_like mode
|
||||
** is enabled then the column must use the default BINARY collating
|
||||
** sequence, or if case_sensitive_like mode is disabled then the column
|
||||
** must use the built-in NOCASE collating sequence.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
pRight = pList->a[0].pExpr;
|
||||
op = pRight->op;
|
||||
@@ -689,9 +683,9 @@ static int isLikeOrGlob(
|
||||
while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){
|
||||
cnt++;
|
||||
}
|
||||
if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){
|
||||
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
|
||||
Expr *pPrefix;
|
||||
*pisComplete = z[cnt]==wc[0] && z[cnt+1]==0;
|
||||
*pisComplete = c==wc[0] && z[cnt+1]==0;
|
||||
pPrefix = sqlite3Expr(db, TK_STRING, z);
|
||||
if( pPrefix ) pPrefix->u.zToken[cnt] = 0;
|
||||
*ppPrefix = pPrefix;
|
||||
@@ -1030,6 +1024,8 @@ static void exprAnalyzeOrTerm(
|
||||
/* At this point, okToChngToIN is true if original pTerm satisfies
|
||||
** case 1. In that case, construct a new virtual term that is
|
||||
** pTerm converted into an IN operator.
|
||||
**
|
||||
** EV: R-00211-15100
|
||||
*/
|
||||
if( okToChngToIN ){
|
||||
Expr *pDup; /* A transient duplicate expression */
|
||||
@@ -1246,6 +1242,7 @@ static void exprAnalyze(
|
||||
Expr *pNewExpr2;
|
||||
int idxNew1;
|
||||
int idxNew2;
|
||||
CollSeq *pColl; /* Collating sequence to use */
|
||||
|
||||
pLeft = pExpr->x.pList->a[1].pExpr;
|
||||
pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
||||
@@ -1260,17 +1257,23 @@ static void exprAnalyze(
|
||||
** inequality. To avoid this, make sure to also run the full
|
||||
** LIKE on all candidate expressions by clearing the isComplete flag
|
||||
*/
|
||||
if( c=='A'-1 ) isComplete = 0;
|
||||
if( c=='A'-1 ) isComplete = 0; /* EV: R-64339-08207 */
|
||||
|
||||
|
||||
c = sqlite3UpperToLower[c];
|
||||
}
|
||||
*pC = c + 1;
|
||||
}
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprDup(db,pLeft,0),pStr1,0);
|
||||
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, noCase ? "NOCASE" : "BINARY",0);
|
||||
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
|
||||
sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
|
||||
pStr1, 0);
|
||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew1==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew1);
|
||||
pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprDup(db,pLeft,0),pStr2,0);
|
||||
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
|
||||
sqlite3ExprSetColl(sqlite3ExprDup(db,pLeft,0), pColl),
|
||||
pStr2, 0);
|
||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
testcase( idxNew2==0 );
|
||||
exprAnalyze(pSrc, pWC, idxNew2);
|
||||
@@ -2022,7 +2025,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
|
||||
}
|
||||
}
|
||||
sqlite3DbFree(pParse->db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
pVtab->zErrMsg = 0;
|
||||
|
||||
for(i=0; i<p->nConstraint; i++){
|
||||
@@ -2887,6 +2890,9 @@ static void bestIndex(
|
||||
** in the ON clause. The term is disabled in (3) because it is not part
|
||||
** of a LEFT OUTER JOIN. In (1), the term is not disabled.
|
||||
**
|
||||
** IMPLEMENTATION-OF: R-24597-58655 No tests are done for terms that are
|
||||
** completely satisfied by indices.
|
||||
**
|
||||
** Disabling a term causes that term to not be tested in the inner loop
|
||||
** of the join. Disabling is an optimization. When terms are satisfied
|
||||
** by indices, we disable them to prevent redundant tests in the inner
|
||||
@@ -3098,6 +3104,7 @@ static int codeAllEqualityTerms(
|
||||
/* The following true for indices with redundant columns.
|
||||
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
||||
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
||||
if( r1!=regBase+j ){
|
||||
if( nReg==1 ){
|
||||
@@ -3241,6 +3248,7 @@ static Bitmask codeOneLoopStart(
|
||||
assert( pTerm->pExpr!=0 );
|
||||
assert( pTerm->leftCursor==iCur );
|
||||
assert( omitTable==0 );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
|
||||
addrNxt = pLevel->addrNxt;
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
||||
@@ -3281,6 +3289,7 @@ static Bitmask codeOneLoopStart(
|
||||
assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
|
||||
assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
|
||||
|
||||
testcase( pStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
pX = pStart->pExpr;
|
||||
assert( pX!=0 );
|
||||
assert( pStart->leftCursor==iCur );
|
||||
@@ -3298,6 +3307,7 @@ static Bitmask codeOneLoopStart(
|
||||
pX = pEnd->pExpr;
|
||||
assert( pX!=0 );
|
||||
assert( pEnd->leftCursor==iCur );
|
||||
testcase( pEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
memEndValue = ++pParse->nMem;
|
||||
sqlite3ExprCode(pParse, pX->pRight, memEndValue);
|
||||
if( pX->op==TK_LT || pX->op==TK_GT ){
|
||||
@@ -3355,7 +3365,7 @@ static Bitmask codeOneLoopStart(
|
||||
** constraints but an index is selected anyway, in order
|
||||
** to force the output order to conform to an ORDER BY.
|
||||
*/
|
||||
int aStartOp[] = {
|
||||
static const u8 aStartOp[] = {
|
||||
0,
|
||||
0,
|
||||
OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */
|
||||
@@ -3365,12 +3375,12 @@ static Bitmask codeOneLoopStart(
|
||||
OP_SeekGe, /* 6: (start_constraints && startEq && !bRev) */
|
||||
OP_SeekLe /* 7: (start_constraints && startEq && bRev) */
|
||||
};
|
||||
int aEndOp[] = {
|
||||
static const u8 aEndOp[] = {
|
||||
OP_Noop, /* 0: (!end_constraints) */
|
||||
OP_IdxGE, /* 1: (end_constraints && !bRev) */
|
||||
OP_IdxLT /* 2: (end_constraints && bRev) */
|
||||
};
|
||||
int nEq = pLevel->plan.nEq;
|
||||
int nEq = pLevel->plan.nEq; /* Number of == or IN terms */
|
||||
int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */
|
||||
int regBase; /* Base register holding constraint values */
|
||||
int r1; /* Temp register */
|
||||
@@ -3380,10 +3390,10 @@ static Bitmask codeOneLoopStart(
|
||||
int endEq; /* True if range end uses ==, >= or <= */
|
||||
int start_constraints; /* Start of range is constrained */
|
||||
int nConstraint; /* Number of constraint terms */
|
||||
Index *pIdx; /* The index we will be using */
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
Index *pIdx; /* The index we will be using */
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
char *zStartAff; /* Affinity for start of range constraint */
|
||||
char *zEndAff; /* Affinity for end of range constraint */
|
||||
|
||||
@@ -3465,6 +3475,7 @@ static Bitmask codeOneLoopStart(
|
||||
}
|
||||
}
|
||||
nConstraint++;
|
||||
testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
}else if( isMinQuery ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
nConstraint++;
|
||||
@@ -3504,6 +3515,7 @@ static Bitmask codeOneLoopStart(
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
|
||||
nConstraint++;
|
||||
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
}
|
||||
sqlite3DbFree(pParse->db, zStartAff);
|
||||
sqlite3DbFree(pParse->db, zEndAff);
|
||||
@@ -3710,11 +3722,15 @@ static Bitmask codeOneLoopStart(
|
||||
|
||||
/* Insert code to test every subexpression that can be completely
|
||||
** computed using the current set of tables.
|
||||
**
|
||||
** IMPLEMENTATION-OF: R-49525-50935 Terms that cannot be satisfied through
|
||||
** the use of indices become tests that are evaluated against each row of
|
||||
** the relevant input tables.
|
||||
*/
|
||||
k = 0;
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ){
|
||||
@@ -3742,7 +3758,7 @@ static Bitmask codeOneLoopStart(
|
||||
VdbeComment((v, "record LEFT JOIN hit"));
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
|
||||
testcase( pTerm->wtFlags & TERM_CODED );
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( (pTerm->prereqAll & notReady)!=0 ){
|
||||
@@ -3960,7 +3976,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
initMaskSet(pMaskSet);
|
||||
whereClauseInit(pWC, pParse, pMaskSet);
|
||||
sqlite3ExprCodeConstants(pParse, pWhere);
|
||||
whereSplit(pWC, pWhere, TK_AND);
|
||||
whereSplit(pWC, pWhere, TK_AND); /* IMP: R-15842-53296 */
|
||||
|
||||
/* Special case: a WHERE clause that is constant. Evaluate the
|
||||
** expression and either jump over all of the code or fall thru.
|
||||
@@ -4048,6 +4064,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
int bestJ = -1; /* The value of j */
|
||||
Bitmask m; /* Bitmask value for j or bestJ */
|
||||
int isOptimal; /* Iterator for optimal/non-optimal search */
|
||||
int nUnconstrained; /* Number tables without INDEXED BY */
|
||||
Bitmask notIndexed; /* Mask of tables that cannot use an index */
|
||||
|
||||
memset(&bestPlan, 0, sizeof(bestPlan));
|
||||
bestPlan.rCost = SQLITE_BIG_DBL;
|
||||
@@ -4089,8 +4107,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** algorithm may choose to use t2 for the outer loop, which is a much
|
||||
** costlier approach.
|
||||
*/
|
||||
nUnconstrained = 0;
|
||||
notIndexed = 0;
|
||||
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
|
||||
Bitmask mask; /* Mask of tables not yet ready */
|
||||
Bitmask mask; /* Mask of tables not yet ready */
|
||||
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
|
||||
int doNotReorder; /* True if this table should not be reordered */
|
||||
WhereCost sCost; /* Cost information from best[Virtual]Index() */
|
||||
@@ -4105,6 +4125,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
mask = (isOptimal ? m : notReady);
|
||||
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
|
||||
if( pTabItem->pIndex==0 ) nUnconstrained++;
|
||||
|
||||
assert( pTabItem->pTab );
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
@@ -4118,9 +4139,43 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
assert( isOptimal || (sCost.used¬Ready)==0 );
|
||||
|
||||
if( (sCost.used¬Ready)==0
|
||||
&& (bestJ<0 || sCost.rCost<bestPlan.rCost
|
||||
|| (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
|
||||
/* If an INDEXED BY clause is present, then the plan must use that
|
||||
** index if it uses any index at all */
|
||||
assert( pTabItem->pIndex==0
|
||||
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|
||||
|| sCost.plan.u.pIdx==pTabItem->pIndex );
|
||||
|
||||
if( isOptimal && (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
|
||||
notIndexed |= m;
|
||||
}
|
||||
|
||||
/* Conditions under which this table becomes the best so far:
|
||||
**
|
||||
** (1) The table must not depend on other tables that have not
|
||||
** yet run.
|
||||
**
|
||||
** (2) A full-table-scan plan cannot supercede another plan unless
|
||||
** it is an "optimal" plan as defined above.
|
||||
**
|
||||
** (3) All tables have an INDEXED BY clause or this table lacks an
|
||||
** INDEXED BY clause or this table uses the specific
|
||||
** index specified by its INDEXED BY clause. This rule ensures
|
||||
** that a best-so-far is always selected even if an impossible
|
||||
** combination of INDEXED BY clauses are given. The error
|
||||
** will be detected and relayed back to the application later.
|
||||
** The NEVER() comes about because rule (2) above prevents
|
||||
** An indexable full-table-scan from reaching rule (3).
|
||||
**
|
||||
** (4) The plan cost must be lower than prior plans or else the
|
||||
** cost must be the same and the number of rows must be lower.
|
||||
*/
|
||||
if( (sCost.used¬Ready)==0 /* (1) */
|
||||
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */
|
||||
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
|
||||
&& (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
|
||||
|| NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
|
||||
&& (bestJ<0 || sCost.rCost<bestPlan.rCost /* (4) */
|
||||
|| (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
|
||||
){
|
||||
WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
|
||||
sCost.rCost, sCost.nRow));
|
||||
|
||||
+16
-1
@@ -268,6 +268,22 @@ do_test analyze3-2.5 {
|
||||
set like "%a"
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like }
|
||||
} {999 999 100}
|
||||
do_test analyze3-2.6 {
|
||||
set like "a"
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like }
|
||||
} {101 0 0}
|
||||
do_test analyze3-2.7 {
|
||||
set like "ab"
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like }
|
||||
} {11 0 0}
|
||||
do_test analyze3-2.8 {
|
||||
set like "abc"
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like }
|
||||
} {2 0 1}
|
||||
do_test analyze3-2.9 {
|
||||
set like "a_c"
|
||||
sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like }
|
||||
} {101 0 10}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -387,7 +403,6 @@ do_test analyze3-3.6.5 {
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test analyze3-3.7.1 {
|
||||
breakpoint
|
||||
set S [sqlite3_prepare_v2 db {
|
||||
SELECT * FROM t1 WHERE a IN (
|
||||
?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?33,
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
# 2010 August 19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing that the current version of SQLite
|
||||
# is capable of reading and writing databases created by previous
|
||||
# versions, and vice-versa.
|
||||
#
|
||||
# To use this test, old versions of the testfixture process should be
|
||||
# copied into the working directory alongside the new version. The old
|
||||
# versions should be named "testfixtureXXX" (or testfixtureXXX.exe on
|
||||
# windows), where XXX can be any string.
|
||||
#
|
||||
# This test file uses the tcl code for controlling a second testfixture
|
||||
# process located in lock_common.tcl. See the commments in lock_common.tcl
|
||||
# for documentation of the available commands.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
db close
|
||||
|
||||
# Search for binaries to test against. Any executable files that match
|
||||
# our naming convention are assumed to be testfixture binaries to test
|
||||
# against.
|
||||
#
|
||||
set binaries [list]
|
||||
set pattern "[file tail [info nameofexec]]?*"
|
||||
if {$tcl_platform(platform)=="windows"} {
|
||||
set pattern [string map {\.exe {}} $pattern]
|
||||
}
|
||||
foreach file [glob -nocomplain $pattern] {
|
||||
if {[file executable $file]} {lappend binaries $file}
|
||||
}
|
||||
if {[llength $binaries]==0} {
|
||||
puts "WARNING: No historical binaries to test against."
|
||||
puts "WARNING: No backwards-compatibility tests have been run."
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
proc get_version {binary} {
|
||||
set chan [launch_testfixture $binary]
|
||||
set v [testfixture $chan { sqlite3 -version }]
|
||||
close $chan
|
||||
set v
|
||||
}
|
||||
foreach bin $binaries {
|
||||
puts -nonewline "Testing against $bin - "
|
||||
flush stdout
|
||||
puts "version [get_version $bin]"
|
||||
}
|
||||
|
||||
proc do_backcompat_test {rv bin1 bin2 script} {
|
||||
|
||||
file delete -force test.db
|
||||
|
||||
if {$bin1 != ""} { set ::bc_chan1 [launch_testfixture $bin1] }
|
||||
set ::bc_chan2 [launch_testfixture $bin2]
|
||||
|
||||
if { $rv } {
|
||||
proc code2 {tcl} { uplevel #0 $tcl }
|
||||
if {$bin1 != ""} { proc code2 {tcl} { testfixture $::bc_chan1 $tcl } }
|
||||
proc code1 {tcl} { testfixture $::bc_chan2 $tcl }
|
||||
} else {
|
||||
proc code1 {tcl} { uplevel #0 $tcl }
|
||||
if {$bin1 != ""} { proc code1 {tcl} { testfixture $::bc_chan1 $tcl } }
|
||||
proc code2 {tcl} { testfixture $::bc_chan2 $tcl }
|
||||
}
|
||||
|
||||
proc sql1 sql { code1 [list db eval $sql] }
|
||||
proc sql2 sql { code2 [list db eval $sql] }
|
||||
|
||||
code1 { sqlite3 db test.db }
|
||||
code2 { sqlite3 db test.db }
|
||||
|
||||
uplevel $script
|
||||
|
||||
catch { code1 { db close } }
|
||||
catch { code2 { db close } }
|
||||
catch { close $::bc_chan2 }
|
||||
catch { close $::bc_chan1 }
|
||||
}
|
||||
|
||||
array set ::incompatible [list]
|
||||
proc do_allbackcompat_test {script} {
|
||||
|
||||
foreach bin $::binaries {
|
||||
set nErr [set_test_counter errors]
|
||||
foreach dir {0 1} {
|
||||
|
||||
set bintag [string map {testfixture {}} $bin]
|
||||
set bintag [string map {\.exe {}} $bintag]
|
||||
if {$bintag == ""} {set bintag self}
|
||||
set ::bcname ".$bintag.$dir."
|
||||
|
||||
rename do_test _do_test
|
||||
proc do_test {nm sql res} {
|
||||
set nm [regsub {\.} $nm $::bcname]
|
||||
uplevel [list _do_test $nm $sql $res]
|
||||
}
|
||||
|
||||
do_backcompat_test $dir {} $bin $script
|
||||
|
||||
rename do_test {}
|
||||
rename _do_test do_test
|
||||
}
|
||||
if { $nErr < [set_test_counter errors] } {
|
||||
set ::incompatible([get_version $bin]) 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc read_file {zFile} {
|
||||
set zData {}
|
||||
if {[file exists $zFile]} {
|
||||
set fd [open $zFile]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
|
||||
if {[file size $zFile]<=$::sqlite_pending_byte || $zFile != "test.db"} {
|
||||
set zData [read $fd]
|
||||
} else {
|
||||
set zData [read $fd $::sqlite_pending_byte]
|
||||
append zData [string repeat x 512]
|
||||
seek $fd [expr $::sqlite_pending_byte+512] start
|
||||
append zData [read $fd]
|
||||
}
|
||||
|
||||
close $fd
|
||||
}
|
||||
return $zData
|
||||
}
|
||||
proc write_file {zFile zData} {
|
||||
set fd [open $zFile w]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
puts -nonewline $fd $zData
|
||||
close $fd
|
||||
}
|
||||
proc read_file_system {} {
|
||||
set ret [list]
|
||||
foreach f {test.db test.db-journal test.db-wal} { lappend ret [read_file $f] }
|
||||
set ret
|
||||
}
|
||||
proc write_file_system {data} {
|
||||
foreach f {test.db test.db-journal test.db-wal} d $data {
|
||||
if {[string length $d] == 0} {
|
||||
file delete -force $f
|
||||
} else {
|
||||
write_file $f $d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Actual tests begin here.
|
||||
#
|
||||
# This first block of tests checks to see that the same database and
|
||||
# journal files can be used by old and new versions. WAL and wal-index
|
||||
# files are tested separately below.
|
||||
#
|
||||
do_allbackcompat_test {
|
||||
|
||||
# Test that database files are backwards compatible.
|
||||
#
|
||||
do_test backcompat-1.1.1 { sql1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
|
||||
INSERT INTO t1 VALUES('abc', 'def');
|
||||
} } {}
|
||||
do_test backcompat-1.1.2 { sql2 { SELECT * FROM t1; } } {abc def}
|
||||
do_test backcompat-1.1.3 { sql2 { INSERT INTO t1 VALUES('ghi', 'jkl'); } } {}
|
||||
do_test backcompat-1.1.4 { sql1 { SELECT * FROM t1; } } {abc def ghi jkl}
|
||||
do_test backcompat-1.1.5 { sql1 { PRAGMA integrity_check } } {ok}
|
||||
do_test backcompat-1.1.6 { sql2 { PRAGMA integrity_check } } {ok}
|
||||
|
||||
# Test that one version can roll back a hot-journal file left in the
|
||||
# file-system by the other version.
|
||||
#
|
||||
# Each test case is named "backcompat-1.X...", where X is either 0 or
|
||||
# 1. If it is 0, then the current version creates a journal file that
|
||||
# the old versions try to read. Otherwise, if X is 1, then the old version
|
||||
# creates the journal file and we try to read it with the current version.
|
||||
#
|
||||
do_test backcompat-1.2.1 { sql1 {
|
||||
PRAGMA cache_size = 10;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(randomblob(400), randomblob(400));
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
|
||||
COMMIT;
|
||||
} } {}
|
||||
set cksum1 [sql1 {SELECT md5sum(a), md5sum(b) FROM t1}]
|
||||
set cksum2 [sql2 {SELECT md5sum(a), md5sum(b) FROM t1}]
|
||||
do_test backcompat-1.2.2 [list string compare $cksum1 $cksum2] 0
|
||||
|
||||
do_test backcompat-1.2.3 { sql1 {
|
||||
BEGIN;
|
||||
UPDATE t1 SET a = randomblob(500);
|
||||
} } {}
|
||||
set data [read_file_system]
|
||||
|
||||
do_test backcompat-1.2.4 { sql1 { COMMIT } } {}
|
||||
|
||||
set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
|
||||
do_test backcompat-1.2.5 [list set {} $same] 0
|
||||
|
||||
code1 { db close }
|
||||
code2 { db close }
|
||||
write_file_system $data
|
||||
code1 { sqlite3 db test.db }
|
||||
code2 { sqlite3 db test.db }
|
||||
|
||||
set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
|
||||
do_test backcompat-1.2.6 [list set {} $same] 1
|
||||
|
||||
do_test backcompat-1.2.7 { sql1 { PRAGMA integrity_check } } {ok}
|
||||
do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok}
|
||||
}
|
||||
foreach k [lsort [array names ::incompatible]] {
|
||||
puts "ERROR: Detected journal incompatibility with version $k"
|
||||
}
|
||||
unset ::incompatible
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that WAL and wal-index files may be shared between different
|
||||
# SQLite versions.
|
||||
#
|
||||
do_allbackcompat_test {
|
||||
if {[code1 {sqlite3 -version}] >= "3.7.0"
|
||||
&& [code2 {sqlite3 -version}] >= "3.7.0"
|
||||
} {
|
||||
|
||||
do_test backcompat-2.1.1 { sql1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
|
||||
INSERT INTO t1 VALUES('I', 1);
|
||||
INSERT INTO t1 VALUES('II', 2);
|
||||
INSERT INTO t1 VALUES('III', 3);
|
||||
SELECT * FROM t1;
|
||||
} } {wal I 1 II 2 III 3}
|
||||
do_test backcompat-2.1.2 { sql2 {
|
||||
SELECT * FROM t1;
|
||||
} } {I 1 II 2 III 3}
|
||||
|
||||
set data [read_file_system]
|
||||
code1 {db close}
|
||||
code2 {db close}
|
||||
write_file_system $data
|
||||
code1 {sqlite3 db test.db}
|
||||
code2 {sqlite3 db test.db}
|
||||
|
||||
# The WAL file now in the file-system was created by the [code1]
|
||||
# process. Check that the [code2] process can recover the log.
|
||||
#
|
||||
do_test backcompat-2.1.3 { sql2 {
|
||||
SELECT * FROM t1;
|
||||
} } {I 1 II 2 III 3}
|
||||
do_test backcompat-2.1.4 { sql1 {
|
||||
SELECT * FROM t1;
|
||||
} } {I 1 II 2 III 3}
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -789,4 +789,26 @@ do_test conflict-12.4 {
|
||||
} {2 one}
|
||||
|
||||
|
||||
# Ticket [c38baa3d969eab7946dc50ba9d9b4f0057a19437]
|
||||
# REPLACE works like ABORT on a CHECK constraint.
|
||||
#
|
||||
do_test conflict-13.1 {
|
||||
execsql {
|
||||
CREATE TABLE t13(a CHECK(a!=2));
|
||||
BEGIN;
|
||||
REPLACE INTO t13 VALUES(1);
|
||||
}
|
||||
catchsql {
|
||||
REPLACE INTO t13 VALUES(2);
|
||||
}
|
||||
} {1 {constraint failed}}
|
||||
do_test conflict-13.2 {
|
||||
execsql {
|
||||
REPLACE INTO t13 VALUES(3);
|
||||
COMMIT;
|
||||
SELECT * FROM t13;
|
||||
}
|
||||
} {1 3}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+298
-1
@@ -33,7 +33,7 @@ do_test dbstatus-1.1 {
|
||||
set sz2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
|
||||
set ::PAGESZ [expr {$sz2-$sz1}]
|
||||
set ::BASESZ [expr {$sz1-$::PAGESZ}]
|
||||
expr {$::PAGESZ>1024 && $::PAGESZ<1200}
|
||||
expr {$::PAGESZ>1024 && $::PAGESZ<1300}
|
||||
} {1}
|
||||
do_test dbstatus-1.2 {
|
||||
db eval {
|
||||
@@ -42,4 +42,301 @@ do_test dbstatus-1.2 {
|
||||
lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
|
||||
} [expr {$BASESZ + 10*$PAGESZ}]
|
||||
|
||||
|
||||
proc lookaside {db} {
|
||||
expr { $::lookaside_buffer_size *
|
||||
[lindex [sqlite3_db_status $db SQLITE_DBSTATUS_LOOKASIDE_USED 0] 1]
|
||||
}
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Run the dbstatus-2 and dbstatus-3 tests with several of different
|
||||
# lookaside buffer sizes.
|
||||
#
|
||||
foreach ::lookaside_buffer_size {0 64 120} {
|
||||
|
||||
# Do not run any of these tests if there is SQL configured to run
|
||||
# as part of the [sqlite3] command. This prevents the script from
|
||||
# configuring the size of the lookaside buffer after [sqlite3] has
|
||||
# returned.
|
||||
if {[presql] != ""} break
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests for SQLITE_DBSTATUS_SCHEMA_USED.
|
||||
#
|
||||
# Each test in the following block works as follows. Each test uses a
|
||||
# different database schema.
|
||||
#
|
||||
# 1. Open a connection to an empty database. Disable statement caching.
|
||||
#
|
||||
# 2. Execute the SQL to create the database schema. Measure the total
|
||||
# heap and lookaside memory allocated by SQLite, and the memory
|
||||
# allocated for the database schema according to sqlite3_db_status().
|
||||
#
|
||||
# 3. Drop all tables in the database schema. Measure the total memory
|
||||
# and the schema memory again.
|
||||
#
|
||||
# 4. Repeat step 2.
|
||||
#
|
||||
# 5. Repeat step 3.
|
||||
#
|
||||
# Then test that:
|
||||
#
|
||||
# a) The difference in schema memory quantities in steps 2 and 3 is the
|
||||
# same as the difference in total memory in steps 2 and 3.
|
||||
#
|
||||
# b) Step 4 reports the same amount of schema and total memory used as
|
||||
# in step 2.
|
||||
#
|
||||
# c) Step 5 reports the same amount of schema and total memory used as
|
||||
# in step 3.
|
||||
#
|
||||
foreach {tn schema} {
|
||||
1 { CREATE TABLE t1(a, b) }
|
||||
2 { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1, c UNIQUE) }
|
||||
3 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
4 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE TRIGGER AFTER INSERT ON t1 BEGIN
|
||||
INSERT INTO t2 VALUES(new.a, new.b);
|
||||
SELECT * FROM t1, t2 WHERE a=c AND b=d GROUP BY b HAVING a>5 ORDER BY a;
|
||||
END;
|
||||
}
|
||||
5 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2;
|
||||
}
|
||||
6 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(a,b);
|
||||
CREATE INDEX i3 ON t1(b,b);
|
||||
INSERT INTO t1 VALUES(randomblob(20), randomblob(25));
|
||||
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
|
||||
INSERT INTO t1 SELECT randomblob(20), randomblob(25) FROM t1;
|
||||
ANALYZE;
|
||||
}
|
||||
7 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE VIEW v1 AS
|
||||
SELECT * FROM t1
|
||||
UNION
|
||||
SELECT * FROM t2
|
||||
UNION ALL
|
||||
SELECT c||b, d||a FROM t2 LEFT OUTER JOIN t1 GROUP BY c, d
|
||||
ORDER BY 1, 2
|
||||
;
|
||||
CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN
|
||||
SELECT * FROM v1;
|
||||
UPDATE t1 SET a=5, b=(SELECT c FROM t2);
|
||||
END;
|
||||
SELECT * FROM v1;
|
||||
}
|
||||
8x {
|
||||
CREATE TABLE t1(a, b, UNIQUE(a, b));
|
||||
CREATE VIRTUAL TABLE t2 USING echo(t1);
|
||||
}
|
||||
} {
|
||||
set tn "$::lookaside_buffer_size-$tn"
|
||||
|
||||
# Step 1.
|
||||
db close
|
||||
file delete -force test.db
|
||||
sqlite3 db test.db
|
||||
sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
|
||||
db cache size 0
|
||||
|
||||
catch { register_echo_module db }
|
||||
ifcapable !vtab { if {[string match *x $tn]} continue }
|
||||
|
||||
# Step 2.
|
||||
execsql $schema
|
||||
set nAlloc1 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc1 [lookaside db]
|
||||
set nSchema1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
|
||||
|
||||
# Step 3.
|
||||
drop_all_tables
|
||||
set nAlloc2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc2 [lookaside db]
|
||||
set nSchema2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
|
||||
|
||||
# Step 4.
|
||||
execsql $schema
|
||||
set nAlloc3 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc3 [lookaside db]
|
||||
set nSchema3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
|
||||
|
||||
# Step 5.
|
||||
drop_all_tables
|
||||
set nAlloc4 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc4 [lookaside db]
|
||||
set nSchema4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_SCHEMA_USED 0] 1]
|
||||
set nFree [expr {$nAlloc1-$nAlloc2}]
|
||||
|
||||
# Tests for which the test name ends in an "x" report slightly less
|
||||
# memory than is actually freed when all schema items are finalized.
|
||||
# This is because memory allocated by virtual table implementations
|
||||
# for any reason is not counted as "schema memory".
|
||||
#
|
||||
# Additionally, in auto-vacuum mode, dropping tables and indexes causes
|
||||
# the page-cache to shrink. So the amount of memory freed is always
|
||||
# much greater than just that reported by DBSTATUS_SCHEMA_USED in this
|
||||
# case.
|
||||
#
|
||||
if {[string match *x $tn] || $AUTOVACUUM} {
|
||||
do_test dbstatus-2.$tn.ax { expr {($nSchema1-$nSchema2)<=$nFree} } 1
|
||||
} else {
|
||||
do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree
|
||||
}
|
||||
|
||||
do_test dbstatus-2.$tn.b { list $nAlloc1 $nSchema1 } "$nAlloc3 $nSchema3"
|
||||
do_test dbstatus-2.$tn.c { list $nAlloc2 $nSchema2 } "$nAlloc4 $nSchema4"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests for SQLITE_DBSTATUS_STMT_USED.
|
||||
#
|
||||
# Each test in the following block works as follows. Each test uses a
|
||||
# different database schema.
|
||||
#
|
||||
# 1. Open a connection to an empty database. Initialized the database
|
||||
# schema.
|
||||
#
|
||||
# 2. Prepare a bunch of SQL statements. Measure the total heap and
|
||||
# lookaside memory allocated by SQLite, and the memory allocated
|
||||
# for the prepared statements according to sqlite3_db_status().
|
||||
#
|
||||
# 3. Finalize all prepared statements Measure the total memory
|
||||
# and the prepared statement memory again.
|
||||
#
|
||||
# 4. Repeat step 2.
|
||||
#
|
||||
# 5. Repeat step 3.
|
||||
#
|
||||
# Then test that:
|
||||
#
|
||||
# a) The difference in schema memory quantities in steps 2 and 3 is the
|
||||
# same as the difference in total memory in steps 2 and 3.
|
||||
#
|
||||
# b) Step 4 reports the same amount of schema and total memory used as
|
||||
# in step 2.
|
||||
#
|
||||
# c) Step 5 reports the same amount of schema and total memory used as
|
||||
# in step 3.
|
||||
#
|
||||
foreach {tn schema statements} {
|
||||
1 { CREATE TABLE t1(a, b) } {
|
||||
SELECT * FROM t1;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
UPDATE t1 SET a=5;
|
||||
DELETE FROM t1;
|
||||
}
|
||||
2 {
|
||||
PRAGMA recursive_triggers = 1;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
|
||||
INSERT INTO t1 VALUES(new.a-1, new.b);
|
||||
END;
|
||||
} {
|
||||
INSERT INTO t1 VALUES(5, 'x');
|
||||
}
|
||||
3 {
|
||||
PRAGMA recursive_triggers = 1;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a, b);
|
||||
CREATE TRIGGER tr1 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
|
||||
INSERT INTO t2 VALUES(new.a-1, new.b);
|
||||
END;
|
||||
CREATE TRIGGER tr2 AFTER INSERT ON t1 WHEN (new.a>0) BEGIN
|
||||
INSERT INTO t1 VALUES(new.a-1, new.b);
|
||||
END;
|
||||
} {
|
||||
INSERT INTO t1 VALUES(10, 'x');
|
||||
}
|
||||
4 {
|
||||
CREATE TABLE t1(a, b);
|
||||
} {
|
||||
SELECT count(*) FROM t1 WHERE upper(a)='ABC';
|
||||
}
|
||||
5x {
|
||||
CREATE TABLE t1(a, b UNIQUE);
|
||||
CREATE VIRTUAL TABLE t2 USING echo(t1);
|
||||
} {
|
||||
SELECT count(*) FROM t2;
|
||||
SELECT * FROM t2 WHERE b>5;
|
||||
SELECT * FROM t2 WHERE b='abcdefg';
|
||||
}
|
||||
} {
|
||||
set tn "$::lookaside_buffer_size-$tn"
|
||||
|
||||
# Step 1.
|
||||
db close
|
||||
file delete -force test.db
|
||||
sqlite3 db test.db
|
||||
sqlite3_db_config_lookaside db 0 $::lookaside_buffer_size 500
|
||||
db cache size 1000
|
||||
|
||||
catch { register_echo_module db }
|
||||
ifcapable !vtab { if {[string match *x $tn]} continue }
|
||||
|
||||
execsql $schema
|
||||
db cache flush
|
||||
|
||||
# Step 2.
|
||||
execsql $statements
|
||||
set nAlloc1 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc1 [lookaside db]
|
||||
set nStmt1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
|
||||
execsql $statements
|
||||
|
||||
# Step 3.
|
||||
db cache flush
|
||||
set nAlloc2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc2 [lookaside db]
|
||||
set nStmt2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
|
||||
|
||||
# Step 3.
|
||||
execsql $statements
|
||||
set nAlloc3 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc3 [lookaside db]
|
||||
set nStmt3 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
|
||||
execsql $statements
|
||||
|
||||
# Step 4.
|
||||
db cache flush
|
||||
set nAlloc4 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
incr nAlloc4 [lookaside db]
|
||||
set nStmt4 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_STMT_USED 0] 1]
|
||||
|
||||
set nFree [expr {$nAlloc1-$nAlloc2}]
|
||||
|
||||
do_test dbstatus-3.$tn.a { expr $nStmt2 } {0}
|
||||
|
||||
# Tests for which the test name ends in an "x" report slightly less
|
||||
# memory than is actually freed when all statements are finalized.
|
||||
# This is because a small amount of memory allocated by a virtual table
|
||||
# implementation using sqlite3_mprintf() is technically considered
|
||||
# external and so is not counted as "statement memory".
|
||||
#
|
||||
#puts "$nStmt1 $nFree"
|
||||
if {[string match *x $tn]} {
|
||||
do_test dbstatus-3.$tn.bx { expr $nStmt1<=$nFree } {1}
|
||||
} else {
|
||||
do_test dbstatus-3.$tn.b { expr $nStmt1==$nFree } {1}
|
||||
}
|
||||
|
||||
do_test dbstatus-3.$tn.c { list $nAlloc1 $nStmt1 } [list $nAlloc3 $nStmt3]
|
||||
do_test dbstatus-3.$tn.d { list $nAlloc2 $nStmt2 } [list $nAlloc4 $nStmt4]
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -329,4 +329,778 @@ foreach {n1 rhs} $literals {
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Run some tests on the COLLATE "unary postfix operator".
|
||||
#
|
||||
# This collation sequence reverses both arguments before using
|
||||
# [string compare] to compare them. For example, when comparing the
|
||||
# strings 'one' and 'four', return the result of:
|
||||
#
|
||||
# string compare eno ruof
|
||||
#
|
||||
proc reverse_str {zStr} {
|
||||
set out ""
|
||||
foreach c [split $zStr {}] { set out "${c}${out}" }
|
||||
set out
|
||||
}
|
||||
proc reverse_collate {zLeft zRight} {
|
||||
string compare [reverse_str $zLeft] [reverse_str $zRight]
|
||||
}
|
||||
db collate reverse reverse_collate
|
||||
|
||||
# EVIDENCE-OF: R-59577-33471 The COLLATE operator is a unary postfix
|
||||
# operator that assigns a collating sequence to an expression.
|
||||
#
|
||||
# EVIDENCE-OF: R-23441-22541 The COLLATE operator has a higher
|
||||
# precedence (binds more tightly) than any prefix unary operator or any
|
||||
# binary operator.
|
||||
#
|
||||
do_execsql_test e_expr-9.1 { SELECT 'abcd' < 'bbbb' COLLATE reverse } 0
|
||||
do_execsql_test e_expr-9.2 { SELECT ('abcd' < 'bbbb') COLLATE reverse } 1
|
||||
do_execsql_test e_expr-9.3 { SELECT 'abcd' <= 'bbbb' COLLATE reverse } 0
|
||||
do_execsql_test e_expr-9.4 { SELECT ('abcd' <= 'bbbb') COLLATE reverse } 1
|
||||
|
||||
do_execsql_test e_expr-9.5 { SELECT 'abcd' > 'bbbb' COLLATE reverse } 1
|
||||
do_execsql_test e_expr-9.6 { SELECT ('abcd' > 'bbbb') COLLATE reverse } 0
|
||||
do_execsql_test e_expr-9.7 { SELECT 'abcd' >= 'bbbb' COLLATE reverse } 1
|
||||
do_execsql_test e_expr-9.8 { SELECT ('abcd' >= 'bbbb') COLLATE reverse } 0
|
||||
|
||||
do_execsql_test e_expr-9.10 { SELECT 'abcd' = 'ABCD' COLLATE nocase } 1
|
||||
do_execsql_test e_expr-9.11 { SELECT ('abcd' = 'ABCD') COLLATE nocase } 0
|
||||
do_execsql_test e_expr-9.12 { SELECT 'abcd' == 'ABCD' COLLATE nocase } 1
|
||||
do_execsql_test e_expr-9.13 { SELECT ('abcd' == 'ABCD') COLLATE nocase } 0
|
||||
do_execsql_test e_expr-9.14 { SELECT 'abcd' IS 'ABCD' COLLATE nocase } 1
|
||||
do_execsql_test e_expr-9.15 { SELECT ('abcd' IS 'ABCD') COLLATE nocase } 0
|
||||
|
||||
do_execsql_test e_expr-9.16 { SELECT 'abcd' != 'ABCD' COLLATE nocase } 0
|
||||
do_execsql_test e_expr-9.17 { SELECT ('abcd' != 'ABCD') COLLATE nocase } 1
|
||||
do_execsql_test e_expr-9.18 { SELECT 'abcd' <> 'ABCD' COLLATE nocase } 0
|
||||
do_execsql_test e_expr-9.19 { SELECT ('abcd' <> 'ABCD') COLLATE nocase } 1
|
||||
do_execsql_test e_expr-9.20 { SELECT 'abcd' IS NOT 'ABCD' COLLATE nocase } 0
|
||||
do_execsql_test e_expr-9.21 { SELECT ('abcd' IS NOT 'ABCD') COLLATE nocase } 1
|
||||
|
||||
do_execsql_test e_expr-9.22 {
|
||||
SELECT 'bbb' BETWEEN 'AAA' AND 'CCC' COLLATE nocase
|
||||
} 1
|
||||
do_execsql_test e_expr-9.23 {
|
||||
SELECT ('bbb' BETWEEN 'AAA' AND 'CCC') COLLATE nocase
|
||||
} 0
|
||||
|
||||
# EVIDENCE-OF: R-58731-25439 The collating sequence set by the COLLATE
|
||||
# operator overrides the collating sequence determined by the COLLATE
|
||||
# clause in a table column definition.
|
||||
#
|
||||
do_execsql_test e_expr-9.24 {
|
||||
CREATE TABLE t24(a COLLATE NOCASE, b);
|
||||
INSERT INTO t24 VALUES('aaa', 1);
|
||||
INSERT INTO t24 VALUES('bbb', 2);
|
||||
INSERT INTO t24 VALUES('ccc', 3);
|
||||
} {}
|
||||
do_execsql_test e_expr-9.25 { SELECT 'BBB' = a FROM t24 } {0 1 0}
|
||||
do_execsql_test e_expr-9.25 { SELECT a = 'BBB' FROM t24 } {0 1 0}
|
||||
do_execsql_test e_expr-9.25 { SELECT 'BBB' = a COLLATE binary FROM t24 } {0 0 0}
|
||||
do_execsql_test e_expr-9.25 { SELECT a COLLATE binary = 'BBB' FROM t24 } {0 0 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test statements related to literal values.
|
||||
#
|
||||
# EVIDENCE-OF: R-31536-32008 Literal values may be integers, floating
|
||||
# point numbers, strings, BLOBs, or NULLs.
|
||||
#
|
||||
do_execsql_test e_expr-10.1.1 { SELECT typeof(5) } {integer}
|
||||
do_execsql_test e_expr-10.1.2 { SELECT typeof(5.1) } {real}
|
||||
do_execsql_test e_expr-10.1.3 { SELECT typeof('5.1') } {text}
|
||||
do_execsql_test e_expr-10.1.4 { SELECT typeof(X'ABCD') } {blob}
|
||||
do_execsql_test e_expr-10.1.5 { SELECT typeof(NULL) } {null}
|
||||
|
||||
# EVIDENCE-OF: R-26921-59298 Scientific notation is supported for
|
||||
# floating point literal values.
|
||||
#
|
||||
do_execsql_test e_expr-10.2.1 { SELECT typeof(3.4e-02) } {real}
|
||||
do_execsql_test e_expr-10.2.2 { SELECT typeof(3e+5) } {real}
|
||||
do_execsql_test e_expr-10.2.3 { SELECT 3.4e-02 } {0.034}
|
||||
do_execsql_test e_expr-10.2.4 { SELECT 3e+4 } {30000.0}
|
||||
|
||||
# EVIDENCE-OF: R-35229-17830 A string constant is formed by enclosing
|
||||
# the string in single quotes (').
|
||||
#
|
||||
# EVIDENCE-OF: R-07100-06606 A single quote within the string can be
|
||||
# encoded by putting two single quotes in a row - as in Pascal.
|
||||
#
|
||||
do_execsql_test e_expr-10.3.1 { SELECT 'is not' } {{is not}}
|
||||
do_execsql_test e_expr-10.3.2 { SELECT typeof('is not') } {text}
|
||||
do_execsql_test e_expr-10.3.3 { SELECT 'isn''t' } {isn't}
|
||||
do_execsql_test e_expr-10.3.4 { SELECT typeof('isn''t') } {text}
|
||||
|
||||
# EVIDENCE-OF: R-09593-03321 BLOB literals are string literals
|
||||
# containing hexadecimal data and preceded by a single "x" or "X"
|
||||
# character.
|
||||
#
|
||||
# EVIDENCE-OF: R-39344-59787 For example: X'53514C697465'
|
||||
#
|
||||
do_execsql_test e_expr-10.4.1 { SELECT typeof(X'0123456789ABCDEF') } blob
|
||||
do_execsql_test e_expr-10.4.2 { SELECT typeof(x'0123456789ABCDEF') } blob
|
||||
do_execsql_test e_expr-10.4.3 { SELECT typeof(X'0123456789abcdef') } blob
|
||||
do_execsql_test e_expr-10.4.4 { SELECT typeof(x'0123456789abcdef') } blob
|
||||
do_execsql_test e_expr-10.4.5 { SELECT typeof(X'53514C697465') } blob
|
||||
|
||||
# EVIDENCE-OF: R-23914-51476 A literal value can also be the token
|
||||
# "NULL".
|
||||
#
|
||||
do_execsql_test e_expr-10.5.1 { SELECT NULL } {{}}
|
||||
do_execsql_test e_expr-10.5.2 { SELECT typeof(NULL) } {null}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test statements related to bound parameters
|
||||
#
|
||||
|
||||
proc parameter_test {tn sql params result} {
|
||||
set stmt [sqlite3_prepare_v2 db $sql -1]
|
||||
|
||||
foreach {number name} $params {
|
||||
set nm [sqlite3_bind_parameter_name $stmt $number]
|
||||
do_test $tn.name.$number [list set {} $nm] $name
|
||||
sqlite3_bind_int $stmt $number [expr -1 * $number]
|
||||
}
|
||||
|
||||
sqlite3_step $stmt
|
||||
|
||||
set res [list]
|
||||
for {set i 0} {$i < [sqlite3_column_count $stmt]} {incr i} {
|
||||
lappend res [sqlite3_column_text $stmt $i]
|
||||
}
|
||||
|
||||
set rc [sqlite3_finalize $stmt]
|
||||
do_test $tn.rc [list set {} $rc] SQLITE_OK
|
||||
do_test $tn.res [list set {} $res] $result
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-33509-39458 A question mark followed by a number NNN
|
||||
# holds a spot for the NNN-th parameter. NNN must be between 1 and
|
||||
# SQLITE_MAX_VARIABLE_NUMBER.
|
||||
#
|
||||
set mvn $SQLITE_MAX_VARIABLE_NUMBER
|
||||
parameter_test e_expr-11.1 "
|
||||
SELECT ?1, ?123, ?$SQLITE_MAX_VARIABLE_NUMBER, ?123, ?4
|
||||
" "1 ?1 123 ?123 $mvn ?$mvn 4 ?4" "-1 -123 -$mvn -123 -4"
|
||||
|
||||
set errmsg "variable number must be between ?1 and ?$SQLITE_MAX_VARIABLE_NUMBER"
|
||||
foreach {tn param_number} [list \
|
||||
2 0 \
|
||||
3 [expr $SQLITE_MAX_VARIABLE_NUMBER+1] \
|
||||
4 [expr $SQLITE_MAX_VARIABLE_NUMBER+2] \
|
||||
5 12345678903456789034567890234567890 \
|
||||
6 2147483648 \
|
||||
7 2147483649 \
|
||||
8 4294967296 \
|
||||
9 4294967297 \
|
||||
10 9223372036854775808 \
|
||||
11 9223372036854775809 \
|
||||
12 18446744073709551616 \
|
||||
13 18446744073709551617 \
|
||||
] {
|
||||
do_catchsql_test e_expr-11.1.$tn "SELECT ?$param_number" [list 1 $errmsg]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-33670-36097 A question mark that is not followed by a
|
||||
# number creates a parameter with a number one greater than the largest
|
||||
# parameter number already assigned.
|
||||
#
|
||||
# EVIDENCE-OF: R-42938-07030 If this means the parameter number is
|
||||
# greater than SQLITE_MAX_VARIABLE_NUMBER, it is an error.
|
||||
#
|
||||
parameter_test e_expr-11.2.1 "SELECT ?" {1 {}} -1
|
||||
parameter_test e_expr-11.2.2 "SELECT ?, ?" {1 {} 2 {}} {-1 -2}
|
||||
parameter_test e_expr-11.2.3 "SELECT ?5, ?" {5 ?5 6 {}} {-5 -6}
|
||||
parameter_test e_expr-11.2.4 "SELECT ?, ?5" {1 {} 5 ?5} {-1 -5}
|
||||
parameter_test e_expr-11.2.5 "SELECT ?, ?456, ?" {
|
||||
1 {} 456 ?456 457 {}
|
||||
} {-1 -456 -457}
|
||||
parameter_test e_expr-11.2.5 "SELECT ?, ?456, ?4, ?" {
|
||||
1 {} 456 ?456 4 ?4 457 {}
|
||||
} {-1 -456 -4 -457}
|
||||
foreach {tn sql} [list \
|
||||
1 "SELECT ?$mvn, ?" \
|
||||
2 "SELECT ?[expr $mvn-5], ?, ?, ?, ?, ?, ?" \
|
||||
3 "SELECT ?[expr $mvn], ?5, ?6, ?" \
|
||||
] {
|
||||
do_catchsql_test e_expr-11.3.$tn $sql [list 1 {too many SQL variables}]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-11620-22743 A colon followed by an identifier name
|
||||
# holds a spot for a named parameter with the name :AAAA.
|
||||
#
|
||||
# Identifiers in SQLite consist of alphanumeric, '_' and '$' characters,
|
||||
# and any UTF characters with codepoints larger than 127 (non-ASCII
|
||||
# characters).
|
||||
#
|
||||
parameter_test e_expr-11.2.1 {SELECT :AAAA} {1 :AAAA} -1
|
||||
parameter_test e_expr-11.2.2 {SELECT :123} {1 :123} -1
|
||||
parameter_test e_expr-11.2.3 {SELECT :__} {1 :__} -1
|
||||
parameter_test e_expr-11.2.4 {SELECT :_$_} {1 :_$_} -1
|
||||
parameter_test e_expr-11.2.5 "
|
||||
SELECT :\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25
|
||||
" "1 :\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25" -1
|
||||
parameter_test e_expr-11.2.6 "SELECT :\u0080" "1 :\u0080" -1
|
||||
|
||||
# EVIDENCE-OF: R-49783-61279 An "at" sign works exactly like a colon,
|
||||
# except that the name of the parameter created is @AAAA.
|
||||
#
|
||||
parameter_test e_expr-11.3.1 {SELECT @AAAA} {1 @AAAA} -1
|
||||
parameter_test e_expr-11.3.2 {SELECT @123} {1 @123} -1
|
||||
parameter_test e_expr-11.3.3 {SELECT @__} {1 @__} -1
|
||||
parameter_test e_expr-11.3.4 {SELECT @_$_} {1 @_$_} -1
|
||||
parameter_test e_expr-11.3.5 "
|
||||
SELECT @\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25
|
||||
" "1 @\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25" -1
|
||||
parameter_test e_expr-11.3.6 "SELECT @\u0080" "1 @\u0080" -1
|
||||
|
||||
# EVIDENCE-OF: R-62610-51329 A dollar-sign followed by an identifier
|
||||
# name also holds a spot for a named parameter with the name $AAAA.
|
||||
#
|
||||
# EVIDENCE-OF: R-55025-21042 The identifier name in this case can
|
||||
# include one or more occurrences of "::" and a suffix enclosed in
|
||||
# "(...)" containing any text at all.
|
||||
#
|
||||
# Note: Looks like an identifier cannot consist entirely of "::"
|
||||
# characters or just a suffix. Also, the other named variable characters
|
||||
# (: and @) work the same way internally. Why not just document it that way?
|
||||
#
|
||||
parameter_test e_expr-11.4.1 {SELECT $AAAA} {1 $AAAA} -1
|
||||
parameter_test e_expr-11.4.2 {SELECT $123} {1 $123} -1
|
||||
parameter_test e_expr-11.4.3 {SELECT $__} {1 $__} -1
|
||||
parameter_test e_expr-11.4.4 {SELECT $_$_} {1 $_$_} -1
|
||||
parameter_test e_expr-11.4.5 "
|
||||
SELECT \$\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25
|
||||
" "1 \$\u0e40\u0e2d\u0e28\u0e02\u0e39\u0e40\u0e2d\u0e25" -1
|
||||
parameter_test e_expr-11.4.6 "SELECT \$\u0080" "1 \$\u0080" -1
|
||||
|
||||
parameter_test e_expr-11.5.1 {SELECT $::::a(++--++)} {1 $::::a(++--++)} -1
|
||||
parameter_test e_expr-11.5.2 {SELECT $::a()} {1 $::a()} -1
|
||||
parameter_test e_expr-11.5.3 {SELECT $::1(::#$)} {1 $::1(::#$)} -1
|
||||
|
||||
# EVIDENCE-OF: R-11370-04520 Named parameters are also numbered. The
|
||||
# number assigned is one greater than the largest parameter number
|
||||
# already assigned.
|
||||
#
|
||||
# EVIDENCE-OF: R-42620-22184 If this means the parameter would be
|
||||
# assigned a number greater than SQLITE_MAX_VARIABLE_NUMBER, it is an
|
||||
# error.
|
||||
#
|
||||
parameter_test e_expr-11.6.1 "SELECT ?, @abc" {1 {} 2 @abc} {-1 -2}
|
||||
parameter_test e_expr-11.6.2 "SELECT ?123, :a1" {123 ?123 124 :a1} {-123 -124}
|
||||
parameter_test e_expr-11.6.3 {SELECT $a, ?8, ?, $b, ?2, $c} {
|
||||
1 $a 8 ?8 9 {} 10 $b 2 ?2 11 $c
|
||||
} {-1 -8 -9 -10 -2 -11}
|
||||
foreach {tn sql} [list \
|
||||
1 "SELECT ?$mvn, \$::a" \
|
||||
2 "SELECT ?$mvn, ?4, @a1" \
|
||||
3 "SELECT ?[expr $mvn-2], :bag, @123, \$x" \
|
||||
] {
|
||||
do_catchsql_test e_expr-11.7.$tn $sql [list 1 {too many SQL variables}]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-14068-49671 Parameters that are not assigned values
|
||||
# using sqlite3_bind() are treated as NULL.
|
||||
#
|
||||
do_test e_expr-11.7.1 {
|
||||
set stmt [sqlite3_prepare_v2 db { SELECT ?, :a, @b, $d } -1]
|
||||
sqlite3_step $stmt
|
||||
|
||||
list [sqlite3_column_type $stmt 0] \
|
||||
[sqlite3_column_type $stmt 1] \
|
||||
[sqlite3_column_type $stmt 2] \
|
||||
[sqlite3_column_type $stmt 3]
|
||||
} {NULL NULL NULL NULL}
|
||||
do_test e_expr-11.7.1 { sqlite3_finalize $stmt } SQLITE_OK
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# "Test" the syntax diagrams in lang_expr.html.
|
||||
#
|
||||
# EVIDENCE-OF: R-04177-20688 -- syntax diagram signed-number
|
||||
#
|
||||
do_execsql_test e_expr-12.1.1 { SELECT 0, +0, -0 } {0 0 0}
|
||||
do_execsql_test e_expr-12.1.2 { SELECT 1, +1, -1 } {1 1 -1}
|
||||
do_execsql_test e_expr-12.1.3 { SELECT 2, +2, -2 } {2 2 -2}
|
||||
do_execsql_test e_expr-12.1.4 {
|
||||
SELECT 1.4, +1.4, -1.4
|
||||
} {1.4 1.4 -1.4}
|
||||
do_execsql_test e_expr-12.1.5 {
|
||||
SELECT 1.5e+5, +1.5e+5, -1.5e+5
|
||||
} {150000.0 150000.0 -150000.0}
|
||||
do_execsql_test e_expr-12.1.6 {
|
||||
SELECT 0.0001, +0.0001, -0.0001
|
||||
} {0.0001 0.0001 -0.0001}
|
||||
|
||||
# EVIDENCE-OF: R-30740-26723 -- syntax diagram literal-value
|
||||
#
|
||||
set sqlite_current_time 1
|
||||
do_execsql_test e_expr-12.2.1 {SELECT 123} {123}
|
||||
do_execsql_test e_expr-12.2.2 {SELECT 123.4e05} {12340000.0}
|
||||
do_execsql_test e_expr-12.2.3 {SELECT 'abcde'} {abcde}
|
||||
do_execsql_test e_expr-12.2.4 {SELECT X'414243'} {ABC}
|
||||
do_execsql_test e_expr-12.2.5 {SELECT NULL} {{}}
|
||||
do_execsql_test e_expr-12.2.6 {SELECT CURRENT_TIME} {00:00:01}
|
||||
do_execsql_test e_expr-12.2.7 {SELECT CURRENT_DATE} {1970-01-01}
|
||||
do_execsql_test e_expr-12.2.8 {SELECT CURRENT_TIMESTAMP} {{1970-01-01 00:00:01}}
|
||||
set sqlite_current_time 0
|
||||
|
||||
# EVIDENCE-OF: R-57598-59332 -- syntax diagram expr
|
||||
#
|
||||
file delete -force test.db2
|
||||
execsql {
|
||||
ATTACH 'test.db2' AS dbname;
|
||||
CREATE TABLE dbname.tblname(cname);
|
||||
}
|
||||
|
||||
proc glob {args} {return 1}
|
||||
db function glob glob
|
||||
db function match glob
|
||||
db function regexp glob
|
||||
|
||||
foreach {tn expr} {
|
||||
1 123
|
||||
2 123.4e05
|
||||
3 'abcde'
|
||||
4 X'414243'
|
||||
5 NULL
|
||||
6 CURRENT_TIME
|
||||
7 CURRENT_DATE
|
||||
8 CURRENT_TIMESTAMP
|
||||
|
||||
9 ?
|
||||
10 ?123
|
||||
11 @hello
|
||||
12 :world
|
||||
13 $tcl
|
||||
14 $tcl(array)
|
||||
|
||||
15 cname
|
||||
16 tblname.cname
|
||||
17 dbname.tblname.cname
|
||||
|
||||
18 "+ EXPR"
|
||||
19 "- EXPR"
|
||||
20 "NOT EXPR"
|
||||
21 "~ EXPR"
|
||||
|
||||
22 "EXPR1 || EXPR2"
|
||||
23 "EXPR1 * EXPR2"
|
||||
24 "EXPR1 / EXPR2"
|
||||
25 "EXPR1 % EXPR2"
|
||||
26 "EXPR1 + EXPR2"
|
||||
27 "EXPR1 - EXPR2"
|
||||
28 "EXPR1 << EXPR2"
|
||||
29 "EXPR1 >> EXPR2"
|
||||
30 "EXPR1 & EXPR2"
|
||||
31 "EXPR1 | EXPR2"
|
||||
32 "EXPR1 < EXPR2"
|
||||
33 "EXPR1 <= EXPR2"
|
||||
34 "EXPR1 > EXPR2"
|
||||
35 "EXPR1 >= EXPR2"
|
||||
36 "EXPR1 = EXPR2"
|
||||
37 "EXPR1 == EXPR2"
|
||||
38 "EXPR1 != EXPR2"
|
||||
39 "EXPR1 <> EXPR2"
|
||||
40 "EXPR1 IS EXPR2"
|
||||
41 "EXPR1 IS NOT EXPR2"
|
||||
42 "EXPR1 AND EXPR2"
|
||||
43 "EXPR1 OR EXPR2"
|
||||
|
||||
44 "count(*)"
|
||||
45 "count(DISTINCT EXPR)"
|
||||
46 "substr(EXPR, 10, 20)"
|
||||
47 "changes()"
|
||||
|
||||
48 "( EXPR )"
|
||||
|
||||
49 "CAST ( EXPR AS integer )"
|
||||
50 "CAST ( EXPR AS 'abcd' )"
|
||||
51 "CAST ( EXPR AS 'ab$ $cd' )"
|
||||
|
||||
52 "EXPR COLLATE nocase"
|
||||
53 "EXPR COLLATE binary"
|
||||
|
||||
54 "EXPR1 LIKE EXPR2"
|
||||
55 "EXPR1 LIKE EXPR2 ESCAPE EXPR"
|
||||
56 "EXPR1 GLOB EXPR2"
|
||||
57 "EXPR1 GLOB EXPR2 ESCAPE EXPR"
|
||||
58 "EXPR1 REGEXP EXPR2"
|
||||
59 "EXPR1 REGEXP EXPR2 ESCAPE EXPR"
|
||||
60 "EXPR1 MATCH EXPR2"
|
||||
61 "EXPR1 MATCH EXPR2 ESCAPE EXPR"
|
||||
62 "EXPR1 NOT LIKE EXPR2"
|
||||
63 "EXPR1 NOT LIKE EXPR2 ESCAPE EXPR"
|
||||
64 "EXPR1 NOT GLOB EXPR2"
|
||||
65 "EXPR1 NOT GLOB EXPR2 ESCAPE EXPR"
|
||||
66 "EXPR1 NOT REGEXP EXPR2"
|
||||
67 "EXPR1 NOT REGEXP EXPR2 ESCAPE EXPR"
|
||||
68 "EXPR1 NOT MATCH EXPR2"
|
||||
69 "EXPR1 NOT MATCH EXPR2 ESCAPE EXPR"
|
||||
|
||||
70 "EXPR ISNULL"
|
||||
71 "EXPR NOTNULL"
|
||||
72 "EXPR NOT NULL"
|
||||
|
||||
73 "EXPR1 IS EXPR2"
|
||||
74 "EXPR1 IS NOT EXPR2"
|
||||
|
||||
75 "EXPR NOT BETWEEN EXPR1 AND EXPR2"
|
||||
76 "EXPR BETWEEN EXPR1 AND EXPR2"
|
||||
|
||||
77 "EXPR NOT IN (SELECT cname FROM tblname)"
|
||||
78 "EXPR NOT IN (1)"
|
||||
79 "EXPR NOT IN (1, 2, 3)"
|
||||
80 "EXPR NOT IN tblname"
|
||||
81 "EXPR NOT IN dbname.tblname"
|
||||
82 "EXPR IN (SELECT cname FROM tblname)"
|
||||
83 "EXPR IN (1)"
|
||||
84 "EXPR IN (1, 2, 3)"
|
||||
85 "EXPR IN tblname"
|
||||
86 "EXPR IN dbname.tblname"
|
||||
|
||||
87 "EXISTS (SELECT cname FROM tblname)"
|
||||
88 "NOT EXISTS (SELECT cname FROM tblname)"
|
||||
|
||||
89 "CASE EXPR WHEN EXPR1 THEN EXPR2 ELSE EXPR END"
|
||||
90 "CASE EXPR WHEN EXPR1 THEN EXPR2 END"
|
||||
91 "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE EXPR2 END"
|
||||
92 "CASE EXPR WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"
|
||||
93 "CASE WHEN EXPR1 THEN EXPR2 ELSE EXPR END"
|
||||
94 "CASE WHEN EXPR1 THEN EXPR2 END"
|
||||
95 "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 ELSE EXPR2 END"
|
||||
96 "CASE WHEN EXPR1 THEN EXPR2 WHEN EXPR THEN EXPR1 END"
|
||||
} {
|
||||
|
||||
# If the expression string being parsed contains "EXPR2", then replace
|
||||
# string "EXPR1" and "EXPR2" with arbitrary SQL expressions. If it
|
||||
# contains "EXPR", then replace EXPR with an arbitrary SQL expression.
|
||||
#
|
||||
set elist [list $expr]
|
||||
if {[string match *EXPR2* $expr]} {
|
||||
set elist [list]
|
||||
foreach {e1 e2} { cname "34+22" } {
|
||||
lappend elist [string map [list EXPR1 $e1 EXPR2 $e2] $expr]
|
||||
}
|
||||
}
|
||||
if {[string match *EXPR* $expr]} {
|
||||
set elist2 [list]
|
||||
foreach el $elist {
|
||||
foreach e { cname "34+22" } {
|
||||
lappend elist2 [string map [list EXPR $e] $el]
|
||||
}
|
||||
}
|
||||
set elist $elist2
|
||||
}
|
||||
|
||||
set x 0
|
||||
foreach e $elist {
|
||||
incr x
|
||||
do_test e_expr-12.3.$tn.$x {
|
||||
set rc [catch { execsql "SELECT $e FROM tblname" } msg]
|
||||
} {0}
|
||||
}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-49462-56079 -- syntax diagram raise-function
|
||||
#
|
||||
foreach {tn raiseexpr} {
|
||||
1 "RAISE(IGNORE)"
|
||||
2 "RAISE(ROLLBACK, 'error message')"
|
||||
3 "RAISE(ABORT, 'error message')"
|
||||
4 "RAISE(FAIL, 'error message')"
|
||||
} {
|
||||
do_execsql_test e_expr-12.4.$tn "
|
||||
CREATE TRIGGER dbname.tr$tn BEFORE DELETE ON tblname BEGIN
|
||||
SELECT $raiseexpr ;
|
||||
END;
|
||||
" {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the statements related to the BETWEEN operator.
|
||||
#
|
||||
# EVIDENCE-OF: R-40079-54503 The BETWEEN operator is logically
|
||||
# equivalent to a pair of comparisons. "x BETWEEN y AND z" is equivalent
|
||||
# to "x>=y AND x<=z" except that with BETWEEN, the x expression is
|
||||
# only evaluated once.
|
||||
#
|
||||
db func x x
|
||||
proc x {} { incr ::xcount ; return [expr $::x] }
|
||||
foreach {tn x expr res nEval} {
|
||||
1 10 "x() >= 5 AND x() <= 15" 1 2
|
||||
2 10 "x() BETWEEN 5 AND 15" 1 1
|
||||
|
||||
3 5 "x() >= 5 AND x() <= 5" 1 2
|
||||
4 5 "x() BETWEEN 5 AND 5" 1 1
|
||||
} {
|
||||
do_test e_expr-13.1.$tn {
|
||||
set ::xcount 0
|
||||
set a [execsql "SELECT $expr"]
|
||||
list $::xcount $a
|
||||
} [list $nEval $res]
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-05155-34454 The precedence of the BETWEEN operator is
|
||||
# the same as the precedence as operators == and != and LIKE and groups
|
||||
# left to right.
|
||||
#
|
||||
# Therefore, BETWEEN groups more tightly than operator "AND", but less
|
||||
# so than "<".
|
||||
#
|
||||
do_execsql_test e_expr-13.2.1 { SELECT 1 == 10 BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.2 { SELECT (1 == 10) BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.3 { SELECT 1 == (10 BETWEEN 0 AND 2) } 0
|
||||
do_execsql_test e_expr-13.2.4 { SELECT 6 BETWEEN 4 AND 8 == 1 } 1
|
||||
do_execsql_test e_expr-13.2.5 { SELECT (6 BETWEEN 4 AND 8) == 1 } 1
|
||||
do_execsql_test e_expr-13.2.6 { SELECT 6 BETWEEN 4 AND (8 == 1) } 0
|
||||
|
||||
do_execsql_test e_expr-13.2.7 { SELECT 5 BETWEEN 0 AND 0 != 1 } 1
|
||||
do_execsql_test e_expr-13.2.8 { SELECT (5 BETWEEN 0 AND 0) != 1 } 1
|
||||
do_execsql_test e_expr-13.2.9 { SELECT 5 BETWEEN 0 AND (0 != 1) } 0
|
||||
do_execsql_test e_expr-13.2.10 { SELECT 1 != 0 BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.11 { SELECT (1 != 0) BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.12 { SELECT 1 != (0 BETWEEN 0 AND 2) } 0
|
||||
|
||||
do_execsql_test e_expr-13.2.13 { SELECT 1 LIKE 10 BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.14 { SELECT (1 LIKE 10) BETWEEN 0 AND 2 } 1
|
||||
do_execsql_test e_expr-13.2.15 { SELECT 1 LIKE (10 BETWEEN 0 AND 2) } 0
|
||||
do_execsql_test e_expr-13.2.16 { SELECT 6 BETWEEN 4 AND 8 LIKE 1 } 1
|
||||
do_execsql_test e_expr-13.2.17 { SELECT (6 BETWEEN 4 AND 8) LIKE 1 } 1
|
||||
do_execsql_test e_expr-13.2.18 { SELECT 6 BETWEEN 4 AND (8 LIKE 1) } 0
|
||||
|
||||
do_execsql_test e_expr-13.2.19 { SELECT 0 AND 0 BETWEEN 0 AND 1 } 0
|
||||
do_execsql_test e_expr-13.2.20 { SELECT 0 AND (0 BETWEEN 0 AND 1) } 0
|
||||
do_execsql_test e_expr-13.2.21 { SELECT (0 AND 0) BETWEEN 0 AND 1 } 1
|
||||
do_execsql_test e_expr-13.2.22 { SELECT 0 BETWEEN -1 AND 1 AND 0 } 0
|
||||
do_execsql_test e_expr-13.2.23 { SELECT (0 BETWEEN -1 AND 1) AND 0 } 0
|
||||
do_execsql_test e_expr-13.2.24 { SELECT 0 BETWEEN -1 AND (1 AND 0) } 1
|
||||
|
||||
do_execsql_test e_expr-13.2.25 { SELECT 2 < 3 BETWEEN 0 AND 1 } 1
|
||||
do_execsql_test e_expr-13.2.26 { SELECT (2 < 3) BETWEEN 0 AND 1 } 1
|
||||
do_execsql_test e_expr-13.2.27 { SELECT 2 < (3 BETWEEN 0 AND 1) } 0
|
||||
do_execsql_test e_expr-13.2.28 { SELECT 2 BETWEEN 1 AND 2 < 3 } 0
|
||||
do_execsql_test e_expr-13.2.29 { SELECT 2 BETWEEN 1 AND (2 < 3) } 0
|
||||
do_execsql_test e_expr-13.2.30 { SELECT (2 BETWEEN 1 AND 2) < 3 } 1
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test the statements related to the LIKE and GLOB operators.
|
||||
#
|
||||
# EVIDENCE-OF: R-16584-60189 The LIKE operator does a pattern matching
|
||||
# comparison.
|
||||
#
|
||||
# EVIDENCE-OF: R-11295-04657 The operand to the right of the LIKE
|
||||
# operator contains the pattern and the left hand operand contains the
|
||||
# string to match against the pattern.
|
||||
#
|
||||
do_execsql_test e_expr-14.1.1 { SELECT 'abc%' LIKE 'abcde' } 0
|
||||
do_execsql_test e_expr-14.1.2 { SELECT 'abcde' LIKE 'abc%' } 1
|
||||
|
||||
# EVIDENCE-OF: R-55406-38524 A percent symbol ("%") in the LIKE pattern
|
||||
# matches any sequence of zero or more characters in the string.
|
||||
#
|
||||
do_execsql_test e_expr-14.2.1 { SELECT 'abde' LIKE 'ab%de' } 1
|
||||
do_execsql_test e_expr-14.2.2 { SELECT 'abXde' LIKE 'ab%de' } 1
|
||||
do_execsql_test e_expr-14.2.3 { SELECT 'abABCde' LIKE 'ab%de' } 1
|
||||
|
||||
# EVIDENCE-OF: R-30433-25443 An underscore ("_") in the LIKE pattern
|
||||
# matches any single character in the string.
|
||||
#
|
||||
do_execsql_test e_expr-14.3.1 { SELECT 'abde' LIKE 'ab_de' } 0
|
||||
do_execsql_test e_expr-14.3.2 { SELECT 'abXde' LIKE 'ab_de' } 1
|
||||
do_execsql_test e_expr-14.3.3 { SELECT 'abABCde' LIKE 'ab_de' } 0
|
||||
|
||||
# EVIDENCE-OF: R-59007-20454 Any other character matches itself or its
|
||||
# lower/upper case equivalent (i.e. case-insensitive matching).
|
||||
#
|
||||
do_execsql_test e_expr-14.4.1 { SELECT 'abc' LIKE 'aBc' } 1
|
||||
do_execsql_test e_expr-14.4.2 { SELECT 'aBc' LIKE 'aBc' } 1
|
||||
do_execsql_test e_expr-14.4.3 { SELECT 'ac' LIKE 'aBc' } 0
|
||||
|
||||
# EVIDENCE-OF: R-23648-58527 SQLite only understands upper/lower case
|
||||
# for ASCII characters by default.
|
||||
#
|
||||
# EVIDENCE-OF: R-04532-11527 The LIKE operator is case sensitive by
|
||||
# default for unicode characters that are beyond the ASCII range.
|
||||
#
|
||||
# EVIDENCE-OF: R-44381-11669 the expression
|
||||
# 'a' LIKE 'A' is TRUE but
|
||||
# 'æ' LIKE 'Æ' is FALSE.
|
||||
#
|
||||
do_execsql_test e_expr-14.5.1 { SELECT 'A' LIKE 'a' } 1
|
||||
do_execsql_test e_expr-14.5.2 "SELECT '\u00c6' LIKE '\u00e6'" 0
|
||||
|
||||
# EVIDENCE-OF: R-56683-13731 If the optional ESCAPE clause is present,
|
||||
# then the expression following the ESCAPE keyword must evaluate to a
|
||||
# string consisting of a single character.
|
||||
#
|
||||
do_catchsql_test e_expr-14.6.1 {
|
||||
SELECT 'A' LIKE 'a' ESCAPE '12'
|
||||
} {1 {ESCAPE expression must be a single character}}
|
||||
do_catchsql_test e_expr-14.6.2 {
|
||||
SELECT 'A' LIKE 'a' ESCAPE ''
|
||||
} {1 {ESCAPE expression must be a single character}}
|
||||
do_catchsql_test e_expr-14.6.3 { SELECT 'A' LIKE 'a' ESCAPE 'x' } {0 1}
|
||||
do_catchsql_test e_expr-14.6.4 "SELECT 'A' LIKE 'a' ESCAPE '\u00e6'" {0 1}
|
||||
|
||||
# EVIDENCE-OF: R-02045-23762 This character may be used in the LIKE
|
||||
# pattern to include literal percent or underscore characters.
|
||||
#
|
||||
# EVIDENCE-OF: R-13345-31830 The escape character followed by a percent
|
||||
# symbol (%), underscore (_), or a second instance of the escape
|
||||
# character itself matches a literal percent symbol, underscore, or a
|
||||
# single escape character, respectively.
|
||||
#
|
||||
do_execsql_test e_expr-14.7.1 { SELECT 'abc%' LIKE 'abcX%' ESCAPE 'X' } 1
|
||||
do_execsql_test e_expr-14.7.2 { SELECT 'abc5' LIKE 'abcX%' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.3 { SELECT 'abc' LIKE 'abcX%' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.4 { SELECT 'abcX%' LIKE 'abcX%' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.5 { SELECT 'abc%%' LIKE 'abcX%' ESCAPE 'X' } 0
|
||||
|
||||
do_execsql_test e_expr-14.7.6 { SELECT 'abc_' LIKE 'abcX_' ESCAPE 'X' } 1
|
||||
do_execsql_test e_expr-14.7.7 { SELECT 'abc5' LIKE 'abcX_' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.8 { SELECT 'abc' LIKE 'abcX_' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.9 { SELECT 'abcX_' LIKE 'abcX_' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.10 { SELECT 'abc__' LIKE 'abcX_' ESCAPE 'X' } 0
|
||||
|
||||
do_execsql_test e_expr-14.7.11 { SELECT 'abcX' LIKE 'abcXX' ESCAPE 'X' } 1
|
||||
do_execsql_test e_expr-14.7.12 { SELECT 'abc5' LIKE 'abcXX' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.13 { SELECT 'abc' LIKE 'abcXX' ESCAPE 'X' } 0
|
||||
do_execsql_test e_expr-14.7.14 { SELECT 'abcXX' LIKE 'abcXX' ESCAPE 'X' } 0
|
||||
|
||||
# EVIDENCE-OF: R-51359-17496 The infix LIKE operator is implemented by
|
||||
# calling the application-defined SQL functions like(Y,X) or like(Y,X,Z).
|
||||
#
|
||||
proc likefunc {args} {
|
||||
eval lappend ::likeargs $args
|
||||
return 1
|
||||
}
|
||||
db func like likefunc
|
||||
set ::likeargs [list]
|
||||
do_execsql_test e_expr-15.1.1 { SELECT 'abc' LIKE 'def' } 1
|
||||
do_test e_expr-15.1.2 { set likeargs } {def abc}
|
||||
set ::likeargs [list]
|
||||
do_execsql_test e_expr-15.1.3 { SELECT 'abc' LIKE 'def' ESCAPE 'X' } 1
|
||||
do_test e_expr-15.1.4 { set likeargs } {def abc X}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
||||
# EVIDENCE-OF: R-22868-25880 The LIKE operator can be made case
|
||||
# sensitive using the case_sensitive_like pragma.
|
||||
#
|
||||
do_execsql_test e_expr-16.1.1 { SELECT 'abcxyz' LIKE 'ABC%' } 1
|
||||
do_execsql_test e_expr-16.1.2 { PRAGMA case_sensitive_like = 1 } {}
|
||||
do_execsql_test e_expr-16.1.3 { SELECT 'abcxyz' LIKE 'ABC%' } 0
|
||||
do_execsql_test e_expr-16.1.4 { SELECT 'ABCxyz' LIKE 'ABC%' } 1
|
||||
do_execsql_test e_expr-16.1.5 { PRAGMA case_sensitive_like = 0 } {}
|
||||
do_execsql_test e_expr-16.1.6 { SELECT 'abcxyz' LIKE 'ABC%' } 1
|
||||
do_execsql_test e_expr-16.1.7 { SELECT 'ABCxyz' LIKE 'ABC%' } 1
|
||||
|
||||
# EVIDENCE-OF: R-52087-12043 The GLOB operator is similar to LIKE but
|
||||
# uses the Unix file globbing syntax for its wildcards.
|
||||
#
|
||||
# EVIDENCE-OF: R-09813-17279 Also, GLOB is case sensitive, unlike LIKE.
|
||||
#
|
||||
do_execsql_test e_expr-17.1.1 { SELECT 'abcxyz' GLOB 'abc%' } 0
|
||||
do_execsql_test e_expr-17.1.2 { SELECT 'abcxyz' GLOB 'abc*' } 1
|
||||
do_execsql_test e_expr-17.1.3 { SELECT 'abcxyz' GLOB 'abc___' } 0
|
||||
do_execsql_test e_expr-17.1.4 { SELECT 'abcxyz' GLOB 'abc???' } 1
|
||||
|
||||
do_execsql_test e_expr-17.1.5 { SELECT 'abcxyz' GLOB 'abc*' } 1
|
||||
do_execsql_test e_expr-17.1.6 { SELECT 'ABCxyz' GLOB 'abc*' } 0
|
||||
do_execsql_test e_expr-17.1.7 { SELECT 'abcxyz' GLOB 'ABC*' } 0
|
||||
|
||||
# EVIDENCE-OF: R-39616-20555 Both GLOB and LIKE may be preceded by the
|
||||
# NOT keyword to invert the sense of the test.
|
||||
#
|
||||
do_execsql_test e_expr-17.2.1 { SELECT 'abcxyz' NOT GLOB 'ABC*' } 1
|
||||
do_execsql_test e_expr-17.2.2 { SELECT 'abcxyz' NOT GLOB 'abc*' } 0
|
||||
do_execsql_test e_expr-17.2.3 { SELECT 'abcxyz' NOT LIKE 'ABC%' } 0
|
||||
do_execsql_test e_expr-17.2.4 { SELECT 'abcxyz' NOT LIKE 'abc%' } 0
|
||||
do_execsql_test e_expr-17.2.5 { SELECT 'abdxyz' NOT LIKE 'abc%' } 1
|
||||
|
||||
db nullvalue null
|
||||
do_execsql_test e_expr-17.2.6 { SELECT 'abcxyz' NOT GLOB NULL } null
|
||||
do_execsql_test e_expr-17.2.7 { SELECT 'abcxyz' NOT LIKE NULL } null
|
||||
do_execsql_test e_expr-17.2.8 { SELECT NULL NOT GLOB 'abc*' } null
|
||||
do_execsql_test e_expr-17.2.9 { SELECT NULL NOT LIKE 'ABC%' } null
|
||||
db nullvalue {}
|
||||
|
||||
# EVIDENCE-OF: R-39414-35489 The infix GLOB operator is implemented by
|
||||
# calling the function glob(Y,X) and can be modified by overriding that
|
||||
# function.
|
||||
proc globfunc {args} {
|
||||
eval lappend ::globargs $args
|
||||
return 1
|
||||
}
|
||||
db func glob -argcount 2 globfunc
|
||||
set ::globargs [list]
|
||||
do_execsql_test e_expr-17.3.1 { SELECT 'abc' GLOB 'def' } 1
|
||||
do_test e_expr-17.3.2 { set globargs } {def abc}
|
||||
set ::globargs [list]
|
||||
do_execsql_test e_expr-17.3.3 { SELECT 'X' NOT GLOB 'Y' } 0
|
||||
do_test e_expr-17.3.4 { set globargs } {Y X}
|
||||
sqlite3 db test.db
|
||||
|
||||
# EVIDENCE-OF: R-41650-20872 No regexp() user function is defined by
|
||||
# default and so use of the REGEXP operator will normally result in an
|
||||
# error message.
|
||||
#
|
||||
do_catchsql_test e_expr-18.1.1 {
|
||||
SELECT regexp('abc', 'def')
|
||||
} {1 {no such function: regexp}}
|
||||
do_catchsql_test e_expr-18.1.2 {
|
||||
SELECT 'abc' REGEXP 'def'
|
||||
} {1 {no such function: REGEXP}}
|
||||
|
||||
# EVIDENCE-OF: R-33693-50180 The REGEXP operator is a special syntax for
|
||||
# the regexp() user function.
|
||||
#
|
||||
# EVIDENCE-OF: R-57289-13578 If a application-defined SQL function named
|
||||
# "regexp" is added at run-time, that function will be called in order
|
||||
# to implement the REGEXP operator.
|
||||
#
|
||||
proc regexpfunc {args} {
|
||||
eval lappend ::regexpargs $args
|
||||
return 1
|
||||
}
|
||||
db func regexp -argcount 2 regexpfunc
|
||||
set ::regexpargs [list]
|
||||
do_execsql_test e_expr-18.2.1 { SELECT 'abc' REGEXP 'def' } 1
|
||||
do_test e_expr-18.2.2 { set regexpargs } {def abc}
|
||||
set ::regexpargs [list]
|
||||
do_execsql_test e_expr-18.2.3 { SELECT 'X' NOT REGEXP 'Y' } 0
|
||||
do_test e_expr-18.2.4 { set regexpargs } {Y X}
|
||||
sqlite3 db test.db
|
||||
|
||||
# EVIDENCE-OF: R-42037-37826 The default match() function implementation
|
||||
# raises an exception and is not really useful for anything.
|
||||
#
|
||||
do_catchsql_test e_expr-19.1.1 {
|
||||
SELECT 'abc' MATCH 'def'
|
||||
} {1 {unable to use function MATCH in the requested context}}
|
||||
do_catchsql_test e_expr-19.1.2 {
|
||||
SELECT match('abc', 'def')
|
||||
} {1 {unable to use function MATCH in the requested context}}
|
||||
|
||||
# EVIDENCE-OF: R-37916-47407 The MATCH operator is a special syntax for
|
||||
# the match() application-defined function.
|
||||
#
|
||||
# EVIDENCE-OF: R-06021-09373 But extensions can override the match()
|
||||
# function with more helpful logic.
|
||||
#
|
||||
proc matchfunc {args} {
|
||||
eval lappend ::matchargs $args
|
||||
return 1
|
||||
}
|
||||
db func match -argcount 2 matchfunc
|
||||
set ::matchargs [list]
|
||||
do_execsql_test e_expr-19.2.1 { SELECT 'abc' MATCH 'def' } 1
|
||||
do_test e_expr-19.2.2 { set matchargs } {def abc}
|
||||
set ::matchargs [list]
|
||||
do_execsql_test e_expr-19.2.3 { SELECT 'X' NOT MATCH 'Y' } 0
|
||||
do_test e_expr-19.2.4 { set matchargs } {Y X}
|
||||
sqlite3 db test.db
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -253,6 +253,11 @@ db2 close
|
||||
# from being inspected externally.
|
||||
#
|
||||
if {$tcl_platform(platform) != "windows"} {
|
||||
|
||||
# Return a list of two booleans (either 0 or 1). The first is true
|
||||
# if the named file exists. The second is true only if the file
|
||||
# exists and the first 28 bytes contain at least one non-zero byte.
|
||||
#
|
||||
proc filestate {fname} {
|
||||
set exists 0
|
||||
set content 0
|
||||
@@ -263,6 +268,7 @@ if {$tcl_platform(platform) != "windows"} {
|
||||
}
|
||||
list $exists $content
|
||||
}
|
||||
|
||||
do_test exclusive-3.0 {
|
||||
filestate test.db-journal
|
||||
} {0 0}
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
# 2010 July 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
|
||||
|
||||
file_control_chunksize_test db main [expr 1024*1024]
|
||||
|
||||
do_test fallocate-1.1 {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 1;
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
file size test.db
|
||||
} [expr 1*1024*1024]
|
||||
|
||||
do_test fallocate-1.2 {
|
||||
execsql { INSERT INTO t1 VALUES(1, zeroblob(1024*900)) }
|
||||
file size test.db
|
||||
} [expr 1*1024*1024]
|
||||
|
||||
do_test fallocate-1.3 {
|
||||
execsql { INSERT INTO t1 VALUES(2, zeroblob(1024*900)) }
|
||||
file size test.db
|
||||
} [expr 2*1024*1024]
|
||||
|
||||
do_test fallocate-1.4 {
|
||||
execsql { DELETE FROM t1 WHERE a = 1 }
|
||||
file size test.db
|
||||
} [expr 1*1024*1024]
|
||||
|
||||
do_test fallocate-1.5 {
|
||||
execsql { DELETE FROM t1 WHERE a = 2 }
|
||||
file size test.db
|
||||
} [expr 1*1024*1024]
|
||||
|
||||
do_test fallocate-1.6 {
|
||||
execsql { PRAGMA freelist_count }
|
||||
} {0}
|
||||
|
||||
# Start a write-transaction and read the "database file size" field from
|
||||
# the journal file. This field should be set to the number of pages in
|
||||
# the database file based on the size of the file on disk, not the actual
|
||||
# logical size of the database within the file.
|
||||
#
|
||||
# We need to check this to verify that if in the unlikely event a rollback
|
||||
# causes a database file to grow, the database grows to its previous size
|
||||
# on disk, not to the minimum size required to hold the database image.
|
||||
#
|
||||
do_test fallocate-1.7 {
|
||||
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
|
||||
if {[permutation] != "inmemory_journal"} {
|
||||
hexio_get_int [hexio_read test.db-journal 16 4]
|
||||
} else {
|
||||
set {} 1024
|
||||
}
|
||||
} {1024}
|
||||
do_test fallocate-1.8 { execsql { COMMIT } } {}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests - fallocate-2.* - test that things work in WAL
|
||||
# mode as well.
|
||||
#
|
||||
set skipwaltests [expr {
|
||||
[permutation]=="journaltest" || [permutation]=="inmemory_journal"
|
||||
}]
|
||||
ifcapable !wal { set skipwaltests 1 }
|
||||
|
||||
if {!$skipwaltests} {
|
||||
db close
|
||||
file delete -force test.db
|
||||
sqlite3 db test.db
|
||||
file_control_chunksize_test db main [expr 32*1024]
|
||||
|
||||
do_test fallocate-2.1 {
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(a, b);
|
||||
}
|
||||
file size test.db
|
||||
} [expr 32*1024]
|
||||
|
||||
do_test fallocate-2.2 {
|
||||
execsql { INSERT INTO t1 VALUES(1, zeroblob(35*1024)) }
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
file size test.db
|
||||
} [expr 64*1024]
|
||||
|
||||
do_test fallocate-2.3 {
|
||||
execsql { DELETE FROM t1 }
|
||||
execsql { VACUUM }
|
||||
file size test.db
|
||||
} [expr 64*1024]
|
||||
|
||||
do_test fallocate-2.4 {
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
file size test.db
|
||||
} [expr 32*1024]
|
||||
|
||||
do_test fallocate-2.5 {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(2, randomblob(35*1024));
|
||||
PRAGMA wal_checkpoint;
|
||||
INSERT INTO t1 VALUES(3, randomblob(128));
|
||||
DELETE FROM t1 WHERE a = 2;
|
||||
VACUUM;
|
||||
}
|
||||
file size test.db
|
||||
} [expr 64*1024]
|
||||
|
||||
do_test fallocate-2.6 {
|
||||
sqlite3 db2 test.db
|
||||
execsql { BEGIN ; SELECT count(a) FROM t1 } db2
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(4, randomblob(128));
|
||||
PRAGMA wal_checkpoint;
|
||||
}
|
||||
file size test.db
|
||||
} [expr 64*1024]
|
||||
|
||||
do_test fallocate-2.7 {
|
||||
execsql { SELECT count(b) FROM t1 } db2
|
||||
} {1}
|
||||
|
||||
do_test fallocate-2.8 {
|
||||
execsql { COMMIT } db2
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
file size test.db
|
||||
} [expr 32*1024]
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -1936,5 +1936,50 @@ do_test fkey2-dd08e5.1.6 {
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Verify that ticket ce7c133ea6cc9ccdc1a60d80441f80b6180f5eba
|
||||
# fixed.
|
||||
#
|
||||
do_test fkey2-ce7c13.1.1 {
|
||||
execsql {
|
||||
CREATE TABLE tce71(a INTEGER PRIMARY KEY, b);
|
||||
CREATE UNIQUE INDEX ice71 ON tce71(a,b);
|
||||
INSERT INTO tce71 VALUES(100,200);
|
||||
CREATE TABLE tce72(w, x, y, FOREIGN KEY(x,y) REFERENCES tce71(a,b));
|
||||
INSERT INTO tce72 VALUES(300,100,200);
|
||||
UPDATE tce71 set b = 200 where a = 100;
|
||||
SELECT * FROM tce71, tce72;
|
||||
}
|
||||
} {100 200 300 100 200}
|
||||
do_test fkey2-ce7c13.1.2 {
|
||||
catchsql {
|
||||
UPDATE tce71 set b = 201 where a = 100;
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-ce7c13.1.3 {
|
||||
catchsql {
|
||||
UPDATE tce71 set a = 101 where a = 100;
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-ce7c13.1.4 {
|
||||
execsql {
|
||||
CREATE TABLE tce73(a INTEGER PRIMARY KEY, b, UNIQUE(a,b));
|
||||
INSERT INTO tce73 VALUES(100,200);
|
||||
CREATE TABLE tce74(w, x, y, FOREIGN KEY(x,y) REFERENCES tce73(a,b));
|
||||
INSERT INTO tce74 VALUES(300,100,200);
|
||||
UPDATE tce73 set b = 200 where a = 100;
|
||||
SELECT * FROM tce73, tce74;
|
||||
}
|
||||
} {100 200 300 100 200}
|
||||
do_test fkey2-ce7c13.1.5 {
|
||||
catchsql {
|
||||
UPDATE tce73 set b = 201 where a = 100;
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
do_test fkey2-ce7c13.1.6 {
|
||||
catchsql {
|
||||
UPDATE tce73 set a = 101 where a = 100;
|
||||
}
|
||||
} {1 {foreign key constraint failed}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -114,4 +114,23 @@ do_test icu-4.3 {
|
||||
}
|
||||
} {apricot cherry chokecherry yamot peach plum}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that it is not possible to call the ICU regex() function with
|
||||
# anything other than exactly two arguments. See also:
|
||||
#
|
||||
# http://src.chromium.org/viewvc/chrome/trunk/src/third_party/sqlite/icu-regexp.patch?revision=34807&view=markup
|
||||
#
|
||||
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
|
||||
do_catchsql_test icu-5.2 {
|
||||
SELECT regexp('a[abc]c.*')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.3 {
|
||||
SELECT regexp('a[abc]c.*', 'abc', 'c')
|
||||
} {1 {wrong number of arguments to function regexp()}}
|
||||
do_catchsql_test icu-5.4 {
|
||||
SELECT 'abc' REGEXP 'a[abc]c.*'
|
||||
} {0 1}
|
||||
do_catchsql_test icu-5.4 { SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
|
||||
do_catchsql_test icu-5.5 { SELECT 'abc' REGEXP, 1 } {1 {near ",": syntax error}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -123,6 +123,16 @@ do_test indexedby-4.1 {
|
||||
do_test indexedby-4.2 {
|
||||
EQP { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c }
|
||||
} {0 1 {TABLE t2} 1 0 {TABLE t1 WITH INDEX i1}}
|
||||
do_test indexedby-4.3 {
|
||||
catchsql {
|
||||
SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
|
||||
}
|
||||
} {1 {cannot use index: i1}}
|
||||
do_test indexedby-4.4 {
|
||||
catchsql {
|
||||
SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c
|
||||
}
|
||||
} {1 {cannot use index: i3}}
|
||||
|
||||
# Test embedding an INDEXED BY in a CREATE VIEW statement. This block
|
||||
# also tests that nothing bad happens if an index refered to by
|
||||
|
||||
+12
-17
@@ -91,6 +91,15 @@ foreach locking_mode {normal exclusive} {
|
||||
INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
|
||||
}
|
||||
} {}
|
||||
|
||||
# Open a read-only cursor on table "a". If the COMMIT below is
|
||||
# interrupted by a persistent IO error, the pager will transition to
|
||||
# PAGER_ERROR state. If there are no other read-only cursors open,
|
||||
# from there the pager immediately discards all cached data and
|
||||
# switches to PAGER_OPEN state. This read-only cursor stops that
|
||||
# from happening, leaving the pager stuck in PAGER_ERROR state.
|
||||
#
|
||||
set channel [db incrblob -readonly a Name [db last_insert_rowid]]
|
||||
|
||||
# Now try to commit the transaction. Cause an IO error to occur
|
||||
# within this operation, which moves the pager into the error state.
|
||||
@@ -118,25 +127,11 @@ foreach locking_mode {normal exclusive} {
|
||||
# with the dirty page.
|
||||
#
|
||||
do_test ioerr5-1.$locking_mode-$iFail.3 {
|
||||
set bt [btree_from_db db]
|
||||
sqlite3_soft_heap_limit 1024
|
||||
compilesql16 "SELECT 10"
|
||||
array set stats [btree_pager_stats $bt]
|
||||
} {SQLITE_OK}
|
||||
|
||||
# If the pager made it all the way to PAGER_SYNCED state, then
|
||||
# both in-memory pages are clean. Following the calls to
|
||||
# release_memory() that were made as part of the [compilesql16]
|
||||
# above, there will be zero pages left in the cache.
|
||||
#
|
||||
# If the pager did not make it as far as PAGER_SYNCED, the two
|
||||
# in memory pages are still dirty. So there will be 2 pages left
|
||||
# in the cache following the release_memory() calls.
|
||||
#
|
||||
if {$stats(state)==5} {
|
||||
set nPage 0
|
||||
}
|
||||
expr {$stats(page)==$nPage}
|
||||
} {1}
|
||||
close $channel
|
||||
|
||||
# Ensure that nothing was written to the database while reclaiming
|
||||
# memory from the pager in error state.
|
||||
@@ -148,7 +143,7 @@ foreach locking_mode {normal exclusive} {
|
||||
close $fd
|
||||
expr {$zDatabase eq $zDatabase2}
|
||||
} {1}
|
||||
|
||||
|
||||
if {$rc eq [list 0 {}]} {
|
||||
do_test ioerr5.1-$locking_mode-$iFail.3 {
|
||||
execsql { SELECT count(*) FROM a }
|
||||
|
||||
@@ -524,4 +524,35 @@ ifcapable pragma {
|
||||
do_test jrnlmode-7.2 { file size test.db } {1024}
|
||||
}
|
||||
|
||||
do_execsql_test jrnlmode-8.1 { PRAGMA locking_mode=EXCLUSIVE } {exclusive}
|
||||
do_execsql_test jrnlmode-8.2 { CREATE TABLE t1(x) } {}
|
||||
do_execsql_test jrnlmode-8.3 { INSERT INTO t1 VALUES(123) } {}
|
||||
do_execsql_test jrnlmode-8.4 { SELECT * FROM t1 } {123}
|
||||
do_execsql_test jrnlmode-8.5 { PRAGMA journal_mode=PERSIST } {persist}
|
||||
do_execsql_test jrnlmode-8.6 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.7 { PRAGMA journal_mode=TRUNCATE } {truncate}
|
||||
do_execsql_test jrnlmode-8.8 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.9 { CREATE TABLE t2(y) } {}
|
||||
do_execsql_test jrnlmode-8.10 { INSERT INTO t2 VALUES(456) } {}
|
||||
do_execsql_test jrnlmode-8.11 { SELECT * FROM t1, t2 } {123 456}
|
||||
do_execsql_test jrnlmode-8.12 { PRAGMA locking_mode=NORMAL } {normal}
|
||||
do_execsql_test jrnlmode-8.13 { PRAGMA journal_mode=PERSIST } {persist}
|
||||
do_execsql_test jrnlmode-8.14 { PRAGMA journal_mode=TRUNCATE } {truncate}
|
||||
do_execsql_test jrnlmode-8.15 { PRAGMA journal_mode=PERSIST } {persist}
|
||||
do_execsql_test jrnlmode-8.16 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.17 { PRAGMA journal_mode=TRUNCATE } {truncate}
|
||||
do_execsql_test jrnlmode-8.18 { PRAGMA locking_mode=EXCLUSIVE } {exclusive}
|
||||
do_execsql_test jrnlmode-8.19 { CREATE TABLE t3(z) } {}
|
||||
do_execsql_test jrnlmode-8.20 { BEGIN IMMEDIATE } {}
|
||||
do_execsql_test jrnlmode-8.21 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.22 { COMMIT } {}
|
||||
do_execsql_test jrnlmode-8.23 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.24 { PRAGMA journal_mode=TRUNCATE } {truncate}
|
||||
do_execsql_test jrnlmode-8.25 { PRAGMA locking_mode=NORMAL } {normal}
|
||||
do_execsql_test jrnlmode-8.26 { CREATE TABLE t4(w) } {}
|
||||
do_execsql_test jrnlmode-8.27 { BEGIN IMMEDIATE } {}
|
||||
do_execsql_test jrnlmode-8.28 { PRAGMA journal_mode=DELETE } {delete}
|
||||
do_execsql_test jrnlmode-8.29 { COMMIT } {}
|
||||
do_execsql_test jrnlmode-8.30 { PRAGMA journal_mode=DELETE } {delete}
|
||||
|
||||
finish_test
|
||||
|
||||
+134
@@ -194,6 +194,31 @@ do_test like-3.4 {
|
||||
set sqlite_like_count
|
||||
} 0
|
||||
|
||||
# The LIKE optimization still works when the RHS is a string with no
|
||||
# wildcard. Ticket [e090183531fc2747]
|
||||
#
|
||||
do_test like-3.4.2 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'a' ORDER BY 1;
|
||||
}
|
||||
} {a nosort {} i1}
|
||||
do_test like-3.4.3 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'ab' ORDER BY 1;
|
||||
}
|
||||
} {ab nosort {} i1}
|
||||
do_test like-3.4.4 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'abcd' ORDER BY 1;
|
||||
}
|
||||
} {abcd nosort {} i1}
|
||||
do_test like-3.4.5 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x LIKE 'abcde' ORDER BY 1;
|
||||
}
|
||||
} {nosort {} i1}
|
||||
|
||||
|
||||
# Partial optimization when the pattern does not end in '%'
|
||||
#
|
||||
do_test like-3.5 {
|
||||
@@ -309,6 +334,26 @@ do_test like-3.24 {
|
||||
set sqlite_like_count
|
||||
} 6
|
||||
|
||||
# GLOB optimization when there is no wildcard. Ticket [e090183531fc2747]
|
||||
#
|
||||
do_test like-3.25 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x GLOB 'a' ORDER BY 1;
|
||||
}
|
||||
} {a nosort {} i1}
|
||||
do_test like-3.26 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x GLOB 'abcd' ORDER BY 1;
|
||||
}
|
||||
} {abcd nosort {} i1}
|
||||
do_test like-3.27 {
|
||||
queryplan {
|
||||
SELECT x FROM t1 WHERE x GLOB 'abcde' ORDER BY 1;
|
||||
}
|
||||
} {nosort {} i1}
|
||||
|
||||
|
||||
|
||||
# No optimization if the LHS of the LIKE is not a column name or
|
||||
# if the RHS is not a string.
|
||||
#
|
||||
@@ -733,5 +778,94 @@ do_test like-10.15 {
|
||||
}
|
||||
} {12 123 scan 5 like 6}
|
||||
|
||||
# LIKE and GLOB where the default collating sequence is not appropriate
|
||||
# but an index with the appropriate collating sequence exists.
|
||||
#
|
||||
do_test like-11.0 {
|
||||
execsql {
|
||||
CREATE TABLE t11(
|
||||
a INTEGER PRIMARY KEY,
|
||||
b TEXT COLLATE nocase,
|
||||
c TEXT COLLATE binary
|
||||
);
|
||||
INSERT INTO t11 VALUES(1, 'a','a');
|
||||
INSERT INTO t11 VALUES(2, 'ab','ab');
|
||||
INSERT INTO t11 VALUES(3, 'abc','abc');
|
||||
INSERT INTO t11 VALUES(4, 'abcd','abcd');
|
||||
INSERT INTO t11 VALUES(5, 'A','A');
|
||||
INSERT INTO t11 VALUES(6, 'AB','AB');
|
||||
INSERT INTO t11 VALUES(7, 'ABC','ABC');
|
||||
INSERT INTO t11 VALUES(8, 'ABCD','ABCD');
|
||||
INSERT INTO t11 VALUES(9, 'x','x');
|
||||
INSERT INTO t11 VALUES(10, 'yz','yz');
|
||||
INSERT INTO t11 VALUES(11, 'X','X');
|
||||
INSERT INTO t11 VALUES(12, 'YZ','YZ');
|
||||
SELECT count(*) FROM t11;
|
||||
}
|
||||
} {12}
|
||||
do_test like-11.1 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=OFF;
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd ABC ABCD nosort t11 *}
|
||||
do_test like-11.2 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=ON;
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd nosort t11 *}
|
||||
do_test like-11.3 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=OFF;
|
||||
CREATE INDEX t11b ON t11(b);
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd ABC ABCD sort {} t11b}
|
||||
do_test like-11.4 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=ON;
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd nosort t11 *}
|
||||
do_test like-11.5 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=OFF;
|
||||
DROP INDEX t11b;
|
||||
CREATE INDEX t11bnc ON t11(b COLLATE nocase);
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd ABC ABCD sort {} t11bnc}
|
||||
do_test like-11.6 {
|
||||
queryplan {
|
||||
CREATE INDEX t11bb ON t11(b COLLATE binary);
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd ABC ABCD sort {} t11bnc}
|
||||
do_test like-11.7 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=ON;
|
||||
SELECT b FROM t11 WHERE b LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd sort {} t11bb}
|
||||
do_test like-11.8 {
|
||||
queryplan {
|
||||
PRAGMA case_sensitive_like=OFF;
|
||||
SELECT b FROM t11 WHERE b GLOB 'abc*' ORDER BY a;
|
||||
}
|
||||
} {abc abcd sort {} t11bb}
|
||||
do_test like-11.9 {
|
||||
queryplan {
|
||||
CREATE INDEX t11cnc ON t11(c COLLATE nocase);
|
||||
CREATE INDEX t11cb ON t11(c COLLATE binary);
|
||||
SELECT c FROM t11 WHERE c LIKE 'abc%' ORDER BY a;
|
||||
}
|
||||
} {abc abcd ABC ABCD sort {} t11cnc}
|
||||
do_test like-11.10 {
|
||||
queryplan {
|
||||
SELECT c FROM t11 WHERE c GLOB 'abc*' ORDER BY a;
|
||||
}
|
||||
} {abc abcd sort {} t11cb}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+12
-6
@@ -27,6 +27,8 @@ proc do_multiclient_test {varname script} {
|
||||
set tn 2
|
||||
}] {
|
||||
faultsim_delete_and_reopen
|
||||
|
||||
proc code1 {tcl} { uplevel #0 $tcl }
|
||||
|
||||
# Open connections [db2] and [db3]. Depending on which iteration this
|
||||
# is, the connections may be created in this interpreter, or in
|
||||
@@ -63,15 +65,19 @@ proc do_multiclient_test {varname script} {
|
||||
# channel name is returned that may be passed as the first argument to proc
|
||||
# 'testfixture' to execute a command. The child testfixture process is shut
|
||||
# down by closing the channel.
|
||||
proc launch_testfixture {} {
|
||||
proc launch_testfixture {{prg ""}} {
|
||||
write_main_loop
|
||||
set prg [info nameofexec]
|
||||
if {$prg eq ""} {
|
||||
set prg [file join . testfixture]
|
||||
}
|
||||
if {$prg eq ""} { set prg [info nameofexec] }
|
||||
if {$prg eq ""} { set prg testfixture }
|
||||
if {[file tail $prg]==$prg} { set prg [file join . $prg] }
|
||||
set chan [open "|$prg tf_main.tcl" r+]
|
||||
fconfigure $chan -buffering line
|
||||
testfixture $chan "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
set rc [catch {
|
||||
testfixture $chan "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
}]
|
||||
if {$rc} {
|
||||
testfixture $chan "set ::sqlite_pending_byte $::sqlite_pending_byte"
|
||||
}
|
||||
return $chan
|
||||
}
|
||||
|
||||
|
||||
+51
-44
@@ -92,50 +92,57 @@ set noerr {{0 {}}}
|
||||
# it is possible to use the unlock-notify mechanism to determine when
|
||||
# the ATTACH might succeed.
|
||||
#
|
||||
foreach {
|
||||
tn
|
||||
db1_loaded
|
||||
db2_loaded
|
||||
enable_extended_errors
|
||||
result
|
||||
error1 error2
|
||||
} "
|
||||
0 0 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
1 0 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
2 0 1 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
3 0 1 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
4 1 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
5 1 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
6 1 1 0 $noerr SQLITE_OK SQLITE_OK
|
||||
7 1 1 1 $noerr SQLITE_OK SQLITE_OK
|
||||
" {
|
||||
|
||||
do_test notify3-2.$tn.1 {
|
||||
catch { db1 close }
|
||||
catch { db2 close }
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db2
|
||||
|
||||
sqlite3_extended_result_codes db1 $enable_extended_errors
|
||||
sqlite3_extended_result_codes db2 $enable_extended_errors
|
||||
|
||||
if { $db1_loaded } { db1 eval "SELECT * FROM sqlite_master" }
|
||||
if { $db2_loaded } { db2 eval "SELECT * FROM sqlite_master" }
|
||||
|
||||
db2 eval "BEGIN EXCLUSIVE"
|
||||
catchsql "ATTACH 'test.db2' AS two" db1
|
||||
} $result
|
||||
|
||||
do_test notify3-2.$tn.2 {
|
||||
list [sqlite3_errcode db1] [sqlite3_extended_errcode db1]
|
||||
} [list $error1 $error2]
|
||||
|
||||
do_test notify3-2.$tn.3 {
|
||||
db1 unlock_notify {set invoked 1}
|
||||
set invoked 0
|
||||
db2 eval commit
|
||||
set invoked
|
||||
} [lindex $result 0]
|
||||
# This test does not work for test-permutations that specify SQL to
|
||||
# be executed as part of the [sqlite3] command that opens the database.
|
||||
# Executing such SQL causes SQLite to load the database schema into memory
|
||||
# earlier than expected, causing test cases to fail.
|
||||
#
|
||||
if {[presql] == ""} {
|
||||
foreach {
|
||||
tn
|
||||
db1_loaded
|
||||
db2_loaded
|
||||
enable_extended_errors
|
||||
result
|
||||
error1 error2
|
||||
} "
|
||||
0 0 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
1 0 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
2 0 1 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
3 0 1 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
4 1 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE
|
||||
5 1 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE
|
||||
6 1 1 0 $noerr SQLITE_OK SQLITE_OK
|
||||
7 1 1 1 $noerr SQLITE_OK SQLITE_OK
|
||||
" {
|
||||
|
||||
do_test notify3-2.$tn.1 {
|
||||
catch { db1 close }
|
||||
catch { db2 close }
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db2
|
||||
|
||||
sqlite3_extended_result_codes db1 $enable_extended_errors
|
||||
sqlite3_extended_result_codes db2 $enable_extended_errors
|
||||
|
||||
if { $db1_loaded } { db1 eval "SELECT * FROM sqlite_master" }
|
||||
if { $db2_loaded } { db2 eval "SELECT * FROM sqlite_master" }
|
||||
|
||||
db2 eval "BEGIN EXCLUSIVE"
|
||||
catchsql "ATTACH 'test.db2' AS two" db1
|
||||
} $result
|
||||
|
||||
do_test notify3-2.$tn.2 {
|
||||
list [sqlite3_errcode db1] [sqlite3_extended_errcode db1]
|
||||
} [list $error1 $error2]
|
||||
|
||||
do_test notify3-2.$tn.3 {
|
||||
db1 unlock_notify {set invoked 1}
|
||||
set invoked 0
|
||||
db2 eval commit
|
||||
set invoked
|
||||
} [lindex $result 0]
|
||||
}
|
||||
}
|
||||
catch { db1 close }
|
||||
catch { db2 close }
|
||||
|
||||
+108
-3
@@ -15,7 +15,7 @@ source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
@@ -502,7 +502,7 @@ foreach {tn ofst value result} {
|
||||
|
||||
7 24 511 {1 2 3 4}
|
||||
8 24 513 {1 2 3 4}
|
||||
9 24 65536 {1 2 3 4}
|
||||
9 24 131072 {1 2 3 4}
|
||||
|
||||
10 32 65536 {1 2}
|
||||
} {
|
||||
@@ -1062,6 +1062,10 @@ do_execsql_test pager1-6.8 {
|
||||
} {11}
|
||||
do_execsql_test pager1-6.9 { COMMIT } {}
|
||||
|
||||
do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {10}
|
||||
do_execsql_test pager1-6.11 { SELECT * FROM t11 } {1 2 3 4}
|
||||
do_execsql_test pager1-6.12 { PRAGMA max_page_count } {11}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
|
||||
@@ -1742,7 +1746,7 @@ do_multiclient_test tn {
|
||||
}
|
||||
} {1 2 3 4 5 6}
|
||||
do_test pager1-17.$tn.3.2 {
|
||||
csql1 { INSERT INTO t1 VALUES(3, 4) }
|
||||
csql1 { INSERT INTO t1 VALUES(3, 4) }
|
||||
} {1 {database is locked}}
|
||||
do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
|
||||
}
|
||||
@@ -2232,6 +2236,7 @@ db close
|
||||
tv delete
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test pager1.27.1 {
|
||||
faultsim_delete_and_reopen
|
||||
sqlite3_pager_refcounts db
|
||||
@@ -2243,4 +2248,104 @@ do_test pager1.27.1 {
|
||||
execsql COMMIT
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that attempting to open a write-transaction with
|
||||
# locking_mode=exclusive in WAL mode fails if there are other clients on
|
||||
# the same database.
|
||||
#
|
||||
catch { db close }
|
||||
do_multiclient_test tn {
|
||||
do_test pager1-28.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = WAL;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
} {wal}
|
||||
do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}
|
||||
|
||||
do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
|
||||
do_test pager1-28.$tn.4 {
|
||||
csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
|
||||
} {1 {database is locked}}
|
||||
code2 { db2 close ; sqlite3 db2 test.db }
|
||||
do_test pager1-28.$tn.4 {
|
||||
sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
|
||||
} {}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Normally, when changing from journal_mode=PERSIST to DELETE the pager
|
||||
# attempts to delete the journal file. However, if it cannot obtain a
|
||||
# RESERVED lock on the database file, this step is skipped.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
do_test pager1-28.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = PERSIST;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES('a', 'b');
|
||||
}
|
||||
} {persist}
|
||||
do_test pager1-28.$tn.2 { file exists test.db-journal } 1
|
||||
do_test pager1-28.$tn.3 { sql1 { PRAGMA journal_mode = DELETE } } delete
|
||||
do_test pager1-28.$tn.4 { file exists test.db-journal } 0
|
||||
|
||||
do_test pager1-28.$tn.5 {
|
||||
sql1 {
|
||||
PRAGMA journal_mode = PERSIST;
|
||||
INSERT INTO t1 VALUES('c', 'd');
|
||||
}
|
||||
} {persist}
|
||||
do_test pager1-28.$tn.6 { file exists test.db-journal } 1
|
||||
do_test pager1-28.$tn.7 {
|
||||
sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
|
||||
} {}
|
||||
do_test pager1-28.$tn.8 { file exists test.db-journal } 1
|
||||
do_test pager1-28.$tn.9 { sql1 { PRAGMA journal_mode = DELETE } } delete
|
||||
do_test pager1-28.$tn.10 { file exists test.db-journal } 1
|
||||
|
||||
do_test pager1-28.$tn.11 { sql2 COMMIT } {}
|
||||
do_test pager1-28.$tn.12 { file exists test.db-journal } 0
|
||||
|
||||
do_test pager1-28-$tn.13 {
|
||||
code1 { set channel [db incrblob -readonly t1 a 2] }
|
||||
sql1 {
|
||||
PRAGMA journal_mode = PERSIST;
|
||||
INSERT INTO t1 VALUES('g', 'h');
|
||||
}
|
||||
} {persist}
|
||||
do_test pager1-28.$tn.14 { file exists test.db-journal } 1
|
||||
do_test pager1-28.$tn.15 {
|
||||
sql2 { BEGIN; INSERT INTO t1 VALUES('e', 'f'); }
|
||||
} {}
|
||||
do_test pager1-28.$tn.16 { sql1 { PRAGMA journal_mode = DELETE } } delete
|
||||
do_test pager1-28.$tn.17 { file exists test.db-journal } 1
|
||||
|
||||
do_test pager1-28.$tn.17 { csql2 { COMMIT } } {1 {database is locked}}
|
||||
do_test pager1-28-$tn.18 { code1 { read $channel } } c
|
||||
do_test pager1-28-$tn.19 { code1 { close $channel } } {}
|
||||
do_test pager1-28.$tn.20 { sql2 { COMMIT } } {}
|
||||
}
|
||||
|
||||
do_test pager1-29.1 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = full;
|
||||
PRAGMA locking_mode=exclusive;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
file size test.db
|
||||
} [expr 1024*3]
|
||||
do_test pager1-29.2 {
|
||||
execsql {
|
||||
PRAGMA page_size = 4096;
|
||||
VACUUM;
|
||||
}
|
||||
file size test.db
|
||||
} [expr 4096*3]
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -116,4 +116,36 @@ foreach code [list {
|
||||
db close
|
||||
tv delete
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# pager2-2.1: Test a ROLLBACK with journal_mode=off.
|
||||
# pager2-2.2: Test shrinking the database (auto-vacuum) with
|
||||
# journal_mode=off
|
||||
#
|
||||
do_test pager2-2.1 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
PRAGMA journal_mode = off;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
ROLLBACK;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {off 1 2}
|
||||
do_test pager2-2.2 {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA auto_vacuum = incremental;
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA journal_mode = off;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(zeroblob(5000), zeroblob(5000));
|
||||
DELETE FROM t1;
|
||||
PRAGMA incremental_vacuum;
|
||||
}
|
||||
file size test.db
|
||||
} {3072}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# 2010 June 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
source $testdir/wal_common.tcl
|
||||
|
||||
|
||||
foreach {tn sql res j} {
|
||||
1 "PRAGMA journal_mode = DELETE" delete 0
|
||||
2 "CREATE TABLE t1(a, b)" {} 0
|
||||
3 "PRAGMA locking_mode=EXCLUSIVE" {exclusive} 0
|
||||
4 "INSERT INTO t1 VALUES(1, 2)" {} 1
|
||||
5 "PRAGMA locking_mode=NORMAL" {normal} 1
|
||||
6 "SELECT * FROM t1" {1 2} 0
|
||||
} {
|
||||
do_execsql_test pager3-1.$tn.1 $sql $res
|
||||
do_test pager3-1.$tn.2 { file exists test.db-journal } $j
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
+156
-1
@@ -52,7 +52,7 @@ do_faultsim_test pagerfault-1 -prep {
|
||||
} -body {
|
||||
execsql { SELECT count(*) FROM t1 }
|
||||
} -test {
|
||||
faultsim_test_result {0 4}
|
||||
faultsim_test_result {0 4}
|
||||
faultsim_integrity_check
|
||||
if {[db one { SELECT count(*) FROM t1 }] != 4} {
|
||||
error "Database content appears incorrect"
|
||||
@@ -1078,4 +1078,159 @@ do_faultsim_test pagerfault-22 -prep {
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Provoke an OOM error during a commit of multi-file transaction. One of
|
||||
# the databases written during the transaction is an in-memory database.
|
||||
# This test causes rollback of the in-memory database after CommitPhaseOne()
|
||||
# has successfully returned. i.e. the series of calls for the aborted commit
|
||||
# is:
|
||||
#
|
||||
# PagerCommitPhaseOne(<in-memory-db>) -> SQLITE_OK
|
||||
# PagerCommitPhaseOne(<file-db>) -> SQLITE_IOERR
|
||||
# PagerRollback(<in-memory-db>)
|
||||
# PagerRollback(<file-db>)
|
||||
#
|
||||
do_faultsim_test pagerfault-23 -prep {
|
||||
foreach f [glob -nocomplain test.db*] { file delete -force $f }
|
||||
sqlite3 db :memory:
|
||||
db eval {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE aux.t2(a, b);
|
||||
}
|
||||
} -body {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1,2);
|
||||
INSERT INTO t2 VALUES(3,4);
|
||||
COMMIT;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
do_faultsim_test pagerfault-24 -prep {
|
||||
faultsim_delete_and_reopen
|
||||
db eval { PRAGMA temp_store = file }
|
||||
execsql { CREATE TABLE x(a, b) }
|
||||
} -body {
|
||||
execsql { CREATE TEMP TABLE t1(a, b) }
|
||||
} -test {
|
||||
faultsim_test_result {0 {}} \
|
||||
{1 {unable to open a temporary database file for storing temporary tables}}
|
||||
set ic [db eval { PRAGMA temp.integrity_check }]
|
||||
if {$ic != "ok"} { error "Integrity check: $ic" }
|
||||
}
|
||||
|
||||
proc lockrows {n} {
|
||||
if {$n==0} { return "" }
|
||||
db eval { SELECT * FROM t1 WHERE oid = $n } {
|
||||
return [lockrows [expr {$n-1}]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
do_test pagerfault-25-pre1 {
|
||||
faultsim_delete_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
CREATE TABLE t1(a);
|
||||
INSERT INTO t1 VALUES(a_string(500));
|
||||
INSERT INTO t1 SELECT a_string(500) FROM t1;
|
||||
INSERT INTO t1 SELECT a_string(500) FROM t1;
|
||||
INSERT INTO t1 SELECT a_string(500) FROM t1;
|
||||
INSERT INTO t1 SELECT a_string(500) FROM t1;
|
||||
INSERT INTO t1 SELECT a_string(500) FROM t1;
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test pagerfault-25 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func a_string a_string
|
||||
set ::channel [db incrblob -readonly t1 a 1]
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(a_string(3000));
|
||||
INSERT INTO t1 VALUES(a_string(3000));
|
||||
}
|
||||
} -body {
|
||||
lockrows 30
|
||||
} -test {
|
||||
catch { lockrows 30 }
|
||||
catch { db eval COMMIT }
|
||||
close $::channel
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
do_faultsim_test pagerfault-26 -prep {
|
||||
faultsim_delete_and_reopen
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA journal_mode = truncate;
|
||||
PRAGMA auto_vacuum = full;
|
||||
PRAGMA locking_mode=exclusive;
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
PRAGMA page_size = 4096;
|
||||
}
|
||||
} -body {
|
||||
execsql {
|
||||
VACUUM;
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
|
||||
set contents [db eval {SELECT * FROM t1}]
|
||||
if {$contents != "1 2"} { error "Bad database contents ($contents)" }
|
||||
|
||||
set sz [file size test.db]
|
||||
if {$testrc!=0 && $sz!=1024*3 && $sz!=4096*3} {
|
||||
error "Expected file size to be 3072 or 12288 bytes - actual size $sz bytes"
|
||||
}
|
||||
if {$testrc==0 && $sz!=4096*3} {
|
||||
error "Expected file size to be 12288 bytes - actual size $sz bytes"
|
||||
}
|
||||
}
|
||||
|
||||
do_test pagerfault-27-pre {
|
||||
faultsim_delete_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a UNIQUE, b UNIQUE);
|
||||
INSERT INTO t2 VALUES( a_string(800), a_string(800) );
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
|
||||
INSERT INTO t1 VALUES (a_string(20000), a_string(20000));
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
BEGIN EXCLUSIVE;
|
||||
}
|
||||
set ::channel [db incrblob t1 a 1]
|
||||
} -body {
|
||||
puts $::channel [string repeat abc 6000]
|
||||
flush $::channel
|
||||
} -test {
|
||||
catchsql { UPDATE t2 SET a = a_string(800), b = a_string(800) }
|
||||
catch { close $::channel }
|
||||
catchsql { ROLLBACK }
|
||||
faultsim_integrity_check
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ test_suite "veryquick" -prefix "" -description {
|
||||
This test suite is the same as the "quick" tests, except that some files
|
||||
that test malloc and IO errors are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
|
||||
]
|
||||
|
||||
test_suite "quick" -prefix "" -description {
|
||||
|
||||
@@ -210,4 +210,27 @@ do_test selectC-3.3 {
|
||||
}
|
||||
} {xxx abcxxx yyy defyyy}
|
||||
|
||||
|
||||
proc udf {} { incr ::udf }
|
||||
set ::udf 0
|
||||
db function udf udf
|
||||
|
||||
do_execsql_test selectC-4.1 {
|
||||
create table t_distinct_bug (a, b, c);
|
||||
insert into t_distinct_bug values ('1', '1', 'a');
|
||||
insert into t_distinct_bug values ('1', '2', 'b');
|
||||
insert into t_distinct_bug values ('1', '3', 'c');
|
||||
insert into t_distinct_bug values ('1', '1', 'd');
|
||||
insert into t_distinct_bug values ('1', '2', 'e');
|
||||
insert into t_distinct_bug values ('1', '3', 'f');
|
||||
} {}
|
||||
|
||||
do_execsql_test selectC-4.2 {
|
||||
select a from (select distinct a, b from t_distinct_bug)
|
||||
} {1 1 1}
|
||||
|
||||
do_execsql_test selectC-4.3 {
|
||||
select a, udf() from (select distinct a, b from t_distinct_bug)
|
||||
} {1 1 1 2 1 3}
|
||||
|
||||
finish_test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user