Merge trunk changes, including the addition of FTS5 and pcache1 performance
enhancements. FossilOrigin-Name: db4cbefb8674c6cfff27c1e918741de1885c845c
This commit is contained in:
commit
38151adfe2
@ -1010,14 +1010,12 @@ fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon $(OPTS) fts5parse.y
|
||||
mv fts5parse.c fts5parse.c.orig
|
||||
cat fts5parse.c.orig | sed 's/yy/fts5yy/g' | sed 's/YY/fts5YY/g' \
|
||||
| sed 's/TOKEN/FTS5TOKEN/g' >> fts5parse.c
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
fts5.c: $(FTS5_SRC)
|
||||
$(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl
|
||||
cp $(TOP)/ext/fts5/fts5.h .
|
||||
|
||||
fts5.lo: fts5.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) -DSQLITE_CORE -c fts5.c
|
||||
@ -1205,6 +1203,7 @@ clean:
|
||||
rm -f fuzzershell fuzzershell.exe
|
||||
rm -f fuzzcheck fuzzcheck.exe
|
||||
rm -f sqldiff sqldiff.exe
|
||||
rm -f fts5.c fts5.h fts5parse.*
|
||||
|
||||
distclean: clean
|
||||
rm -f config.log config.status libtool Makefile sqlite3.pc
|
||||
|
@ -1707,16 +1707,12 @@ fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
|
||||
copy $(TOP)\ext\fts5\fts5parse.y .
|
||||
del /Q fts5parse.h 2>NUL
|
||||
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(OPTS) fts5parse.y
|
||||
move fts5parse.c fts5parse.c.orig
|
||||
type fts5parse.c.orig \
|
||||
| $(NAWK) "/.*/ { gsub(/yy/,\"fts5yy\");print }" \
|
||||
| $(NAWK) "/.*/ { gsub(/YY/,\"fts5YY\");print }" \
|
||||
| $(NAWK) "/.*/ { gsub(/TOKEN/,\"FTS5TOKEN\");print }" > $@
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
fts5.c: $(FTS5_SRC)
|
||||
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
|
||||
copy $(TOP)\ext\fts5\fts5.h .
|
||||
|
||||
fts5.lo: fts5.c $(HDR) $(EXTHDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
|
||||
@ -1870,7 +1866,7 @@ clean:
|
||||
del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
|
||||
del /Q sqlite-*-output.vsix 2>NUL
|
||||
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe 2>NUL
|
||||
del /Q fts5.c fts5parse.* 2>NUL
|
||||
del /Q fts5.c fts5.h fts5parse.* 2>NUL
|
||||
|
||||
# Dynamic link library section.
|
||||
#
|
||||
|
@ -4351,6 +4351,7 @@ void sqlite3Fts3DoclistNext(
|
||||
p += sqlite3Fts3GetVarint(p, piDocid);
|
||||
}else{
|
||||
fts3PoslistCopy(0, &p);
|
||||
while( p<&aDoclist[nDoclist] && *p==0 ) p++;
|
||||
if( p>=&aDoclist[nDoclist] ){
|
||||
*pbEof = 1;
|
||||
}else{
|
||||
@ -5757,10 +5758,10 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
int rc = SQLITE_OK;
|
||||
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
|
||||
int bOr = 0;
|
||||
u8 bEof = 0;
|
||||
u8 bTreeEof = 0;
|
||||
Fts3Expr *p; /* Used to iterate from pExpr to root */
|
||||
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
|
||||
int bMatch;
|
||||
|
||||
/* Check if this phrase descends from an OR expression node. If not,
|
||||
** return NULL. Otherwise, the entry that corresponds to docid
|
||||
@ -5794,31 +5795,47 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
pIter = pPhrase->pOrPoslist;
|
||||
iDocid = pPhrase->iOrDocid;
|
||||
if( pCsr->bDesc==bDescDoclist ){
|
||||
bEof = !pPhrase->doclist.nAll ||
|
||||
(pIter >= (pPhrase->doclist.aAll + pPhrase->doclist.nAll));
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
|
||||
sqlite3Fts3DoclistNext(
|
||||
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
|
||||
&pIter, &iDocid, &bEof
|
||||
);
|
||||
}
|
||||
}else{
|
||||
bEof = !pPhrase->doclist.nAll || (pIter && pIter<=pPhrase->doclist.aAll);
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
|
||||
int dummy;
|
||||
sqlite3Fts3DoclistPrev(
|
||||
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
|
||||
&pIter, &iDocid, &dummy, &bEof
|
||||
);
|
||||
}
|
||||
}
|
||||
pPhrase->pOrPoslist = pIter;
|
||||
pPhrase->iOrDocid = iDocid;
|
||||
bMatch = 1;
|
||||
for(p=pNear; p; p=p->pLeft){
|
||||
u8 bEof = 0;
|
||||
Fts3Expr *pTest = p;
|
||||
Fts3Phrase *pPh;
|
||||
assert( pTest->eType==FTSQUERY_NEAR || pTest->eType==FTSQUERY_PHRASE );
|
||||
if( pTest->eType==FTSQUERY_NEAR ) pTest = pTest->pRight;
|
||||
assert( pTest->eType==FTSQUERY_PHRASE );
|
||||
pPh = pTest->pPhrase;
|
||||
|
||||
if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
|
||||
pIter = pPh->pOrPoslist;
|
||||
iDocid = pPh->iOrDocid;
|
||||
if( pCsr->bDesc==bDescDoclist ){
|
||||
bEof = !pPh->doclist.nAll ||
|
||||
(pIter >= (pPh->doclist.aAll + pPh->doclist.nAll));
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
|
||||
sqlite3Fts3DoclistNext(
|
||||
bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
||||
&pIter, &iDocid, &bEof
|
||||
);
|
||||
}
|
||||
}else{
|
||||
bEof = !pPh->doclist.nAll || (pIter && pIter<=pPh->doclist.aAll);
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
|
||||
int dummy;
|
||||
sqlite3Fts3DoclistPrev(
|
||||
bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
||||
&pIter, &iDocid, &dummy, &bEof
|
||||
);
|
||||
}
|
||||
}
|
||||
pPh->pOrPoslist = pIter;
|
||||
pPh->iOrDocid = iDocid;
|
||||
if( bEof || iDocid!=pCsr->iPrevId ) bMatch = 0;
|
||||
}
|
||||
|
||||
if( bMatch ){
|
||||
pIter = pPhrase->pOrPoslist;
|
||||
}else{
|
||||
pIter = 0;
|
||||
}
|
||||
}
|
||||
if( pIter==0 ) return SQLITE_OK;
|
||||
|
||||
|
@ -134,6 +134,7 @@ proc get_api_docs {data} {
|
||||
#
|
||||
set D [get_struct_docs $data [array names M]]
|
||||
|
||||
output "<dl>"
|
||||
foreach {sub docs} $D {
|
||||
if {[info exists M($sub)]} {
|
||||
set hdr $M($sub)
|
||||
@ -142,12 +143,17 @@ proc get_api_docs {data} {
|
||||
set link ""
|
||||
}
|
||||
|
||||
output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
|
||||
set style "padding-left:6ex;font-size:1.4em;display:block"
|
||||
output "<h style=\"$style\"><pre>$hdr</pre></h>"
|
||||
#output "<hr color=#eeeee style=\"margin:1em 8.4ex 0 8.4ex;\"$link>"
|
||||
#set style "padding-left:6ex;font-size:1.4em;display:block"
|
||||
#output "<h style=\"$style\"><pre>$hdr</pre></h>"
|
||||
|
||||
regsub -line {^ *[)]} $hdr ")" hdr
|
||||
output "<dt style=\"white-space:pre;font-family:monospace;font-size:120%\""
|
||||
output "$link>"
|
||||
output "<b>$hdr</b></dt><dd>"
|
||||
|
||||
set mode ""
|
||||
set bEmpty 1
|
||||
set margin " style=margin-top:0.1em"
|
||||
foreach line [split [string trim $docs] "\n"] {
|
||||
if {[string trim $line]==""} {
|
||||
if {$mode != ""} {output "</$mode>"}
|
||||
@ -158,12 +164,15 @@ proc get_api_docs {data} {
|
||||
} else {
|
||||
set mode p
|
||||
}
|
||||
output "<$mode>"
|
||||
output "<$mode$margin>"
|
||||
set margin ""
|
||||
}
|
||||
output $line
|
||||
}
|
||||
if {$mode != ""} {output "</$mode>"}
|
||||
output "</dd>"
|
||||
}
|
||||
output "</dl>"
|
||||
}
|
||||
|
||||
proc get_fts5_struct {data start end} {
|
||||
|
@ -36,6 +36,13 @@ typedef sqlite3_uint64 u64;
|
||||
#define NEVER(x) 0
|
||||
|
||||
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
/*
|
||||
** Constants for the largest and smallest possible 64-bit signed integers.
|
||||
*/
|
||||
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -219,21 +219,14 @@ struct Fts5Cursor {
|
||||
*/
|
||||
#define FTS5CSR_REQUIRE_CONTENT 0x01
|
||||
#define FTS5CSR_REQUIRE_DOCSIZE 0x02
|
||||
#define FTS5CSR_EOF 0x04
|
||||
#define FTS5CSR_FREE_ZRANK 0x08
|
||||
#define FTS5CSR_REQUIRE_RESEEK 0x10
|
||||
#define FTS5CSR_REQUIRE_INST 0x04
|
||||
#define FTS5CSR_EOF 0x08
|
||||
#define FTS5CSR_FREE_ZRANK 0x10
|
||||
#define FTS5CSR_REQUIRE_RESEEK 0x20
|
||||
|
||||
#define BitFlagAllTest(x,y) (((x) & (y))==(y))
|
||||
#define BitFlagTest(x,y) (((x) & (y))!=0)
|
||||
|
||||
/*
|
||||
** Constants for the largest and smallest possible 64-bit signed integers.
|
||||
** These are copied from sqliteInt.h.
|
||||
*/
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
||||
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macros to Set(), Clear() and Test() cursor flags.
|
||||
@ -437,12 +430,12 @@ static int fts5CreateMethod(
|
||||
/*
|
||||
** The different query plans.
|
||||
*/
|
||||
#define FTS5_PLAN_SCAN 1 /* No usable constraint */
|
||||
#define FTS5_PLAN_MATCH 2 /* (<tbl> MATCH ?) */
|
||||
#define FTS5_PLAN_MATCH 0 /* (<tbl> MATCH ?) */
|
||||
#define FTS5_PLAN_SOURCE 1 /* A source cursor for SORTED_MATCH */
|
||||
#define FTS5_PLAN_SPECIAL 2 /* An internal query */
|
||||
#define FTS5_PLAN_SORTED_MATCH 3 /* (<tbl> MATCH ? ORDER BY rank) */
|
||||
#define FTS5_PLAN_ROWID 4 /* (rowid = ?) */
|
||||
#define FTS5_PLAN_SOURCE 5 /* A source cursor for SORTED_MATCH */
|
||||
#define FTS5_PLAN_SPECIAL 6 /* An internal query */
|
||||
#define FTS5_PLAN_SCAN 4 /* No usable constraint */
|
||||
#define FTS5_PLAN_ROWID 5 /* (rowid = ?) */
|
||||
|
||||
/*
|
||||
** Implementation of the xBestIndex method for FTS5 tables. Within the
|
||||
@ -611,10 +604,11 @@ static int fts5StmtType(Fts5Cursor *pCsr){
|
||||
** specific to the previous row stored by the cursor object.
|
||||
*/
|
||||
static void fts5CsrNewrow(Fts5Cursor *pCsr){
|
||||
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE );
|
||||
sqlite3_free(pCsr->aInst);
|
||||
pCsr->aInst = 0;
|
||||
pCsr->nInstCount = 0;
|
||||
CsrFlagSet(pCsr,
|
||||
FTS5CSR_REQUIRE_CONTENT
|
||||
| FTS5CSR_REQUIRE_DOCSIZE
|
||||
| FTS5CSR_REQUIRE_INST
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -629,7 +623,7 @@ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5Auxdata *pData;
|
||||
Fts5Auxdata *pNext;
|
||||
|
||||
fts5CsrNewrow(pCsr);
|
||||
sqlite3_free(pCsr->aInst);
|
||||
if( pCsr->pStmt ){
|
||||
int eStmt = fts5StmtType(pCsr);
|
||||
sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
|
||||
@ -762,41 +756,42 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
|
||||
*/
|
||||
static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
||||
int ePlan = pCsr->ePlan;
|
||||
int bSkip = 0;
|
||||
int rc;
|
||||
|
||||
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
|
||||
assert( (pCsr->ePlan<2)==
|
||||
(pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
|
||||
);
|
||||
|
||||
switch( ePlan ){
|
||||
case FTS5_PLAN_MATCH:
|
||||
case FTS5_PLAN_SOURCE:
|
||||
rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
|
||||
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
}
|
||||
fts5CsrNewrow(pCsr);
|
||||
break;
|
||||
|
||||
case FTS5_PLAN_SPECIAL: {
|
||||
if( pCsr->ePlan<2 ){
|
||||
int bSkip = 0;
|
||||
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
|
||||
rc = sqlite3Fts5ExprNext(pCsr->pExpr, pCsr->iLastRowid);
|
||||
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
break;
|
||||
}
|
||||
|
||||
case FTS5_PLAN_SORTED_MATCH: {
|
||||
rc = fts5SorterNext(pCsr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc!=SQLITE_ROW ){
|
||||
fts5CsrNewrow(pCsr);
|
||||
}else{
|
||||
switch( pCsr->ePlan ){
|
||||
case FTS5_PLAN_SPECIAL: {
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FTS5_PLAN_SORTED_MATCH: {
|
||||
rc = fts5SorterNext(pCsr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
rc = sqlite3_step(pCsr->pStmt);
|
||||
if( rc!=SQLITE_ROW ){
|
||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||
rc = sqlite3_reset(pCsr->pStmt);
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -1522,7 +1517,7 @@ static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
|
||||
*/
|
||||
static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->aInst==0 ){
|
||||
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST) ){
|
||||
Fts5PoslistReader *aIter; /* One iterator for each phrase */
|
||||
int nIter; /* Number of iterators/phrases */
|
||||
int nByte;
|
||||
@ -1564,9 +1559,11 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
|
||||
}
|
||||
|
||||
sqlite3_free(pCsr->aInst);
|
||||
pCsr->aInst = (int*)buf.p;
|
||||
pCsr->nInstCount = nInst;
|
||||
sqlite3_free(aIter);
|
||||
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@ -2223,6 +2220,18 @@ static void fts5Fts5Func(
|
||||
sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of fts5_source_id() function.
|
||||
*/
|
||||
static void fts5SourceIdFunc(
|
||||
sqlite3_context *pCtx, /* Function call context */
|
||||
int nArg, /* Number of args */
|
||||
sqlite3_value **apVal /* Function arguments */
|
||||
){
|
||||
assert( nArg==0 );
|
||||
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@ -2284,6 +2293,11 @@ int sqlite3_fts5_init(
|
||||
db, "fts5", 0, SQLITE_UTF8, p, fts5Fts5Func, 0, 0
|
||||
);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(
|
||||
db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
|
||||
);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ proc fts5_level_segs {tbl} {
|
||||
set sql "SELECT fts5_decode(rowid,block) aS r FROM ${tbl}_data WHERE rowid=10"
|
||||
set ret [list]
|
||||
foreach L [lrange [db one $sql] 1 end] {
|
||||
lappend ret [expr [llength $L] - 2]
|
||||
lappend ret [expr [llength $L] - 3]
|
||||
}
|
||||
set ret
|
||||
}
|
||||
@ -134,7 +134,7 @@ proc fts5_level_segids {tbl} {
|
||||
set ret [list]
|
||||
foreach L [lrange [db one $sql] 1 end] {
|
||||
set lvl [list]
|
||||
foreach S [lrange $L 2 end] {
|
||||
foreach S [lrange $L 3 end] {
|
||||
regexp {id=([1234567890]*)} $S -> segid
|
||||
lappend lvl $segid
|
||||
}
|
||||
|
@ -49,8 +49,18 @@ do_execsql_test 2.1 {
|
||||
}
|
||||
do_test 2.2 {
|
||||
execsql { SELECT fts5_decode(id, block) FROM t1_data WHERE id==10 }
|
||||
} {/{\(structure\) {lvl=0 nMerge=0 {id=[0123456789]* h=1 leaves=1..1}}}/}
|
||||
do_execsql_test 2.3 {
|
||||
} {/{\(structure\) {lvl=0 nMerge=0 nSeg=1 {id=[0123456789]* h=1 leaves=1..1}}}/}
|
||||
|
||||
foreach w {a b c d e f} {
|
||||
do_execsql_test 2.3.$w.asc {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH $w;
|
||||
} {1}
|
||||
do_execsql_test 2.3.$w.desc {
|
||||
SELECT rowid FROM t1 WHERE t1 MATCH $w ORDER BY rowid DESC;
|
||||
} {1}
|
||||
}
|
||||
|
||||
do_execsql_test 2.4 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
@ -190,8 +200,6 @@ for {set i 1} {$i <= 10} {incr i} {
|
||||
execsql { INSERT INTO t1(t1) VALUES('integrity-check'); }
|
||||
} {}
|
||||
}
|
||||
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}
|
||||
#exit
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
@ -205,6 +205,7 @@ foreach {tn2 sql} {
|
||||
execsql { INSERT INTO xx(xx) VALUES('integrity-check') }
|
||||
} {}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test phrase queries.
|
||||
#
|
||||
|
@ -204,10 +204,11 @@ foreach {T create} {
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
|
||||
foreach {bAsc sql} {
|
||||
0 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix ORDER BY rowid DESC}
|
||||
1 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix}
|
||||
0 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix ORDER BY rowid DESC}
|
||||
} {
|
||||
foreach {tn prefix} {
|
||||
1 {a*} 2 {ab*} 3 {abc*} 4 {abcd*} 5 {abcde*}
|
||||
|
@ -81,6 +81,23 @@ do_execsql_test 2.3 {
|
||||
SELECT rowid FROM yy WHERE yy MATCH 'a + b + c';
|
||||
} {-56 -22}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
CREATE VIRTUAL TABLE abc USING fts5(a);
|
||||
INSERT INTO abc(rowid, a) VALUES(1, 'a');
|
||||
BEGIN;
|
||||
INSERT INTO abc(rowid, a) VALUES(2, 'a');
|
||||
}
|
||||
breakpoint
|
||||
do_execsql_test 3.2 {
|
||||
SELECT rowid FROM abc WHERE abc MATCH 'a';
|
||||
} {1 2}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
COMMIT;
|
||||
SELECT rowid FROM abc WHERE abc MATCH 'a';
|
||||
} {1 2}
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -71,7 +71,8 @@ do_execsql_test 2.3 {
|
||||
} $res
|
||||
do_execsql_test 2.4 {
|
||||
UPDATE x1_data SET block = X'';
|
||||
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
-- SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
SELECT count(*) FROM x1_data;
|
||||
} $res
|
||||
|
||||
do_execsql_test 2.5 {
|
||||
@ -83,10 +84,12 @@ set res [db one {SELECT count(*) FROM x1_data}]
|
||||
do_execsql_test 2.6 {
|
||||
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
} $res
|
||||
do_execsql_test 2.7 {
|
||||
UPDATE x1_data SET block = X'';
|
||||
SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
} $res
|
||||
|
||||
# This is really a corruption test...
|
||||
#do_execsql_test 2.7 {
|
||||
# UPDATE x1_data SET block = X'';
|
||||
# SELECT count(fts5_decode(rowid, block)) FROM x1_data;
|
||||
#} $res
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests with very large tokens.
|
||||
|
@ -380,7 +380,7 @@ proc do_isspace_test {tn tokenizer lCp} {
|
||||
}
|
||||
|
||||
set tokenizers [list unicode61]
|
||||
ifcapable icu { lappend tokenizers icu }
|
||||
#ifcapable icu { lappend tokenizers icu }
|
||||
|
||||
# Some tests to check that the tokenizers can both identify white-space
|
||||
# codepoints. All codepoints tested below are of type "Zs" in the
|
||||
|
@ -46,7 +46,6 @@ do_test 1.5 {
|
||||
catchsql { SELECT * FROM t1 WHERE t1 MATCH 'a' }
|
||||
} {1 {invalid fts5 file format (found 3, expected 2) - run 'rebuild'}}
|
||||
|
||||
breakpoint
|
||||
do_test 1.6 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
@ -102,6 +102,7 @@ for {set i 0} {$i < $nOpt} {incr i} {
|
||||
set dbfile [lindex $argv end-1]
|
||||
if {$O(delete)} { file delete -force $dbfile }
|
||||
sqlite3 db $dbfile
|
||||
catch { load_static_extension db fts5 }
|
||||
db func loadfile loadfile
|
||||
|
||||
db transaction {
|
||||
|
@ -24,7 +24,7 @@ set G(src) [string map [list %dir% $srcdir] {
|
||||
|
||||
set G(hdr) {
|
||||
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
|
||||
#if !defined(SQLITE_TEST) || defined(SQLITE_ENABLE_FTS5)
|
||||
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||
# define NDEBUG 1
|
||||
@ -37,9 +37,12 @@ set G(hdr) {
|
||||
|
||||
set G(footer) {
|
||||
|
||||
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
|
||||
#endif /* !defined(SQLITE_TEST) || defined(SQLITE_ENABLE_FTS5) */
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Read and return the entire contents of text file $zFile from disk.
|
||||
#
|
||||
proc readfile {zFile} {
|
||||
set fd [open $zFile]
|
||||
set data [read $fd]
|
||||
@ -47,6 +50,22 @@ proc readfile {zFile} {
|
||||
return $data
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This command returns a string identifying the current sqlite version -
|
||||
# the equivalent of the SQLITE_SOURCE_ID string.
|
||||
#
|
||||
proc fts5_source_id {zDir} {
|
||||
set top [file dirname [file dirname $zDir]]
|
||||
set uuid [string trim [readfile [file join $top manifest.uuid]]]
|
||||
|
||||
set L [split [readfile [file join $top manifest]]]
|
||||
set date [lindex $L [expr [lsearch -exact $L D]+1]]
|
||||
set date [string range $date 0 [string last . $date]-1]
|
||||
set date [string map {T { }} $date]
|
||||
|
||||
return "fts5: $date $uuid"
|
||||
}
|
||||
|
||||
proc fts5c_init {zOut} {
|
||||
global G
|
||||
set G(fd) stdout
|
||||
@ -58,12 +77,20 @@ proc fts5c_init {zOut} {
|
||||
proc fts5c_printfile {zIn} {
|
||||
global G
|
||||
set data [readfile $zIn]
|
||||
puts $G(fd) "#line 1 \"[file tail $zIn]\""
|
||||
set zTail [file tail $zIn]
|
||||
puts $G(fd) "#line 2 \"$zTail\""
|
||||
|
||||
set sub_map [list --FTS5-SOURCE-ID-- [fts5_source_id $::srcdir]]
|
||||
if {$zTail=="fts5parse.c"} {
|
||||
lappend sub_map yy fts5yy YY fts5YY TOKEN FTS5TOKEN
|
||||
}
|
||||
|
||||
foreach line [split $data "\n"] {
|
||||
if {[regexp {^#include.*fts5} $line]} continue
|
||||
if {[regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?sqlite3Fts5} $line]} {
|
||||
set line "static $line"
|
||||
}
|
||||
set line [string map $sub_map $line]
|
||||
puts $G(fd) $line
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,32 @@
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Process command line arguments.
|
||||
#
|
||||
proc usage {} {
|
||||
puts stderr "usage: $::argv0 database table"
|
||||
puts stderr ""
|
||||
exit 1
|
||||
}
|
||||
|
||||
set o(vtab) fts5
|
||||
set o(tok) ""
|
||||
set o(limit) 0
|
||||
set o(automerge) -1
|
||||
set o(crisismerge) -1
|
||||
|
||||
if {[llength $argv]!=2} usage
|
||||
|
||||
set database [lindex $argv 0]
|
||||
set tbl [lindex $argv 1]
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Start of main program.
|
||||
#
|
||||
sqlite3 db $database
|
||||
catch { load_static_extension db fts5 }
|
||||
|
||||
db eval "SELECT fts5_decode(rowid, block) AS d FROM ${tbl}_data WHERE id=10" {
|
||||
foreach lvl [lrange $d 1 end] {
|
||||
puts $lvl
|
||||
puts [lrange $lvl 0 2]
|
||||
foreach seg [lrange $lvl 3 end] {
|
||||
puts " $seg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,5 +168,68 @@ do_multiclient_test tn {
|
||||
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that "PRAGMA data_version" works when an OTA client writes the
|
||||
# database.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
|
||||
# Initialize a target (test.db) and ota (ota.db) database.
|
||||
#
|
||||
forcedelete ota.db
|
||||
sql1 $setup_sql
|
||||
|
||||
# Check the initial database contains table "xx" with a single row.
|
||||
# Also save the current values of "PRAGMA data-version" for [db1]
|
||||
# and [db2].
|
||||
#
|
||||
do_test 2.$tn.1 {
|
||||
list [sql1 { SELECT count(*) FROM xx }] [sql2 { SELECT count(*) FROM xx }]
|
||||
} {1 1}
|
||||
set V1 [sql1 {PRAGMA data_version}]
|
||||
set V2 [sql2 {PRAGMA data_version}]
|
||||
|
||||
# Check the values of data-version have not magically changed.
|
||||
#
|
||||
do_test 2.$tn.2 {
|
||||
list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
|
||||
} [list $V1 $V2]
|
||||
|
||||
# Start stepping the OTA. From the point of view of [db1] and [db2], the
|
||||
# data-version values remain unchanged until the database contents are
|
||||
# modified. At which point the values are incremented.
|
||||
#
|
||||
sqlite3ota ota test.db ota.db
|
||||
set x 0
|
||||
while {[db one {SELECT count(*) FROM xx}]==1} {
|
||||
do_test 2.$tn.3.[incr x] {
|
||||
list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
|
||||
} [list $V1 $V2]
|
||||
ota step
|
||||
}
|
||||
do_test 2.$tn.5.1 { expr {$V1 < [sql1 {PRAGMA data_version}]} } 1
|
||||
do_test 2.$tn.5.2 { expr {$V2 < [sql2 {PRAGMA data_version}]} } 1
|
||||
|
||||
# Check the db contents is as expected.
|
||||
#
|
||||
do_test 2.$tn.4 {
|
||||
list [sql1 {SELECT count(*) FROM xx}] [sql2 {SELECT count(*) FROM xx}]
|
||||
} {3 3}
|
||||
|
||||
set V1 [sql1 {PRAGMA data_version}]
|
||||
set V2 [sql2 {PRAGMA data_version}]
|
||||
|
||||
# Finish applying the OTA (i.e. do the incremental checkpoint). Check that
|
||||
# this does not cause the data-version values to change.
|
||||
#
|
||||
while {[ota step]=="SQLITE_OK"} { }
|
||||
ota close
|
||||
|
||||
do_test 2.$tn.6 {
|
||||
list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}]
|
||||
} [list $V1 $V2]
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
14
main.mk
14
main.mk
@ -77,8 +77,6 @@ LIBOBJ += sqlite3session.o
|
||||
|
||||
LIBOBJ += fts5.o
|
||||
|
||||
|
||||
|
||||
# All of the source code files.
|
||||
#
|
||||
SRC = \
|
||||
@ -313,7 +311,8 @@ TESTSRC += \
|
||||
$(TOP)/ext/misc/totype.c \
|
||||
$(TOP)/ext/misc/wholenumber.c \
|
||||
$(TOP)/ext/misc/vfslog.c \
|
||||
$(TOP)/ext/fts5/fts5_tcl.c
|
||||
$(TOP)/ext/fts5/fts5_tcl.c \
|
||||
fts5.c
|
||||
|
||||
|
||||
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
|
||||
@ -666,18 +665,12 @@ fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
./lemon $(OPTS) fts5parse.y
|
||||
mv fts5parse.c fts5parse.c.orig
|
||||
cat fts5parse.c.orig | sed 's/yy/fts5yy/g' | sed 's/YY/fts5YY/g' \
|
||||
| sed 's/TOKEN/FTS5TOKEN/g' >> fts5parse.c
|
||||
|
||||
fts5parse.h: fts5parse.c
|
||||
|
||||
fts5.c: $(FTS5_SRC)
|
||||
tclsh $(TOP)/ext/fts5/tool/mkfts5c.tcl
|
||||
|
||||
fts5.o: fts5.c $(HDR) $(EXTHDR)
|
||||
$(TCCX) -DSQLITE_CORE -c fts5.c
|
||||
|
||||
cp $(TOP)/ext/fts5/fts5.h .
|
||||
|
||||
|
||||
userauth.o: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
|
||||
@ -895,3 +888,4 @@ clean:
|
||||
rm -f fuzzershell fuzzershell.exe
|
||||
rm -f fuzzcheck fuzzcheck.exe
|
||||
rm -f sqldiff sqldiff.exe
|
||||
rm -f fts5.c fts5.h fts5parse.*
|
||||
|
101
manifest
101
manifest
@ -1,9 +1,9 @@
|
||||
C Merge\sin\sthe\slatest\senhancements\sfrom\strunks,\sespecially\sthe\suse\sof\n_byteswap_ulong()\sand\ssimilar\sintrinsics\son\sMSVC.
|
||||
D 2015-07-02T18:47:12.801
|
||||
C Merge\strunk\schanges,\sincluding\sthe\saddition\sof\sFTS5\sand\spcache1\sperformance\nenhancements.
|
||||
D 2015-07-14T15:39:22.594
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5f96aa7b5ea06cbc72500e85d64f75f4ecd5ed52
|
||||
F Makefile.in 82cd7996d31d7b0a9a80a6c247ad9fd9b41223af
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 0600e09c21aeb7bff79e6badff56a406f68ced22
|
||||
F Makefile.msc 69a5df1f8764b991cb1a269825538258f9097c4c
|
||||
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
|
||||
F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7
|
||||
F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db
|
||||
@ -78,7 +78,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c a95de5190cf52f4fa9d5952890399cab63e632b9
|
||||
F ext/fts3/fts3.c d2f7981f4d7dfeb76aac82a15c7f37f425329c0f
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h 601743955ac43a0e82e6828a931c07bb3b0c95ff
|
||||
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
|
||||
@ -104,16 +104,16 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
|
||||
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
|
||||
F ext/fts3/unicode/mkunicode.tcl 95cf7ec186e48d4985e433ff8a1c89090a774252
|
||||
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
|
||||
F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
|
||||
F ext/fts5/extract_api_docs.tcl 06583c935f89075ea0b32f85efa5dd7619fcbd03
|
||||
F ext/fts5/fts5.h 81d1a92fc2b4bd477af7e4e0b38b456f3e199fba
|
||||
F ext/fts5/fts5Int.h c91773920639c01571d6870ac0c20e960798f79c
|
||||
F ext/fts5/fts5Int.h 8d9bce1847a10df2e4ed9492ea4f3868276748fb
|
||||
F ext/fts5/fts5_aux.c 7cd0e2858171dacf505fea4e2e84ee6126854c3d
|
||||
F ext/fts5/fts5_buffer.c 80f9ba4431848cb857e3d2158f5280093dcd8015
|
||||
F ext/fts5/fts5_config.c b2456e9625bca41c51d54c363e369c6356895c90
|
||||
F ext/fts5/fts5_expr.c d2e148345639c5a5583e0daa39a639bf298ae6a7
|
||||
F ext/fts5/fts5_hash.c 219f4edd72e5cf95b19c33f1058809a18fad5229
|
||||
F ext/fts5/fts5_index.c fb1f0de6b4cd02a212c0c9c5580daa64a5634035
|
||||
F ext/fts5/fts5_main.c c24ee96e7b97178d02e66e1fe1d43f6145aab8f8
|
||||
F ext/fts5/fts5_index.c 1a1fd996dfe2d632df1dd00689553bc0d205497d
|
||||
F ext/fts5/fts5_main.c 2e43726b3ef40b3d5efc0adc7c279d857b1c74fe
|
||||
F ext/fts5/fts5_storage.c 4cae85b5287b159d9d98174a4e70adf872b0930a
|
||||
F ext/fts5/fts5_tcl.c 85eb4e0d0fefa9420b78151496ad4599a1783e20
|
||||
F ext/fts5/fts5_tokenize.c 30f97a8c74683797b4cd233790444fbefb3b0708
|
||||
@ -122,11 +122,11 @@ F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1
|
||||
F ext/fts5/fts5_vocab.c 4e268a3fcbc099e50e335a1135be985a41ff6f7f
|
||||
F ext/fts5/fts5parse.y 833db1101b78c0c47686ab1b84918e38c36e9452
|
||||
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
|
||||
F ext/fts5/test/fts5_common.tcl 9553cce0757092d194307c2168d4edd100eab578
|
||||
F ext/fts5/test/fts5aa.test 0be21c89fd66b588db355a6398911fd875bdcc6c
|
||||
F ext/fts5/test/fts5_common.tcl e0b4a846a7670f6232a644ece69ef25a5c19c0e8
|
||||
F ext/fts5/test/fts5aa.test 4e896b9154764fed48179a87ba0bdf3650d7f49d
|
||||
F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
|
||||
F ext/fts5/test/fts5ac.test 0990ae7497ebaea2ab5f7fd5caedd93a71a905fc
|
||||
F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0
|
||||
F ext/fts5/test/fts5ac.test 9737992d08c56bfd4803e933744d2d764e23795c
|
||||
F ext/fts5/test/fts5ad.test b2edee8b7de0c21d2c88f8a18c195034aad6952d
|
||||
F ext/fts5/test/fts5ae.test ddc558e3e3b52db0101f7541b2e3849b77052c92
|
||||
F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
|
||||
F ext/fts5/test/fts5ag.test ec3e119b728196620a31507ef503c455a7a73505
|
||||
@ -135,7 +135,7 @@ F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37
|
||||
F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8
|
||||
F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592
|
||||
F ext/fts5/test/fts5al.test fc60ebeac9d8e366e71309d4c31fa72199d711d7
|
||||
F ext/fts5/test/fts5alter.test 78b63e088646dd623cacbdc1899a54d638dcf3d8
|
||||
F ext/fts5/test/fts5alter.test 6022c61467a82aa11c70822ccad22b328dcf0d04
|
||||
F ext/fts5/test/fts5auto.test caa5bcf917db11944655a2a9bd38c67c520376ca
|
||||
F ext/fts5/test/fts5aux.test 8c687c948cc98e9a94be014df7d518acc1b3b74f
|
||||
F ext/fts5/test/fts5auxdata.test 141a7cbffcceb1bd2799b4b29c183ff8780d586e
|
||||
@ -169,17 +169,17 @@ F ext/fts5/test/fts5prefix.test 552a462f0e8595676611f41643de217fb4ac2808
|
||||
F ext/fts5/test/fts5rank.test 11dcebba31d822f7e99685b4ea2c2ae3ec0b16f1
|
||||
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
|
||||
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
|
||||
F ext/fts5/test/fts5rowid.test f7674e19a40987bf59624d8db9827114cb7f7a3e
|
||||
F ext/fts5/test/fts5rowid.test 6f9833b23b176dc4aa15b7fc02afeb2b220fd460
|
||||
F ext/fts5/test/fts5tokenizer.test 83e7e01a21ec7fdf814d51f6184cc26bb77d7695
|
||||
F ext/fts5/test/fts5unicode.test fbef8d8a3b4b88470536cc57604a82ca52e51841
|
||||
F ext/fts5/test/fts5unicode2.test 84282d4a6dd34370dc19a3486dd6fecc89c7ed0b
|
||||
F ext/fts5/test/fts5unicode2.test c1dd890ba32b7609adba78e420faa847abe43b59
|
||||
F ext/fts5/test/fts5unicode3.test 35c3d02aa7acf7d43d8de3bfe32c15ba96e8928e
|
||||
F ext/fts5/test/fts5unindexed.test e9539d5b78c677315e7ed8ea911d4fd25437c680
|
||||
F ext/fts5/test/fts5version.test bed59038e937c40d3c0056d08076db7874c6cd4a
|
||||
F ext/fts5/test/fts5version.test c54a708236642bcc850d2aedc6f505fef1d9f9f1
|
||||
F ext/fts5/test/fts5vocab.test cdf97b9678484e9bad5062edf9c9106e5c3b0c5c
|
||||
F ext/fts5/tool/loadfts5.tcl 7ef3e62131f0434a78e4f5c5b056b09d221710a8
|
||||
F ext/fts5/tool/mkfts5c.tcl 7174fce13c9d4b11c702eef3767344066cffe87e
|
||||
F ext/fts5/tool/showfts5.tcl 921f33b30c3189deefd2b2cc81f951638544aaf1
|
||||
F ext/fts5/tool/loadfts5.tcl 95edf0b6b92a09f9ed85595038b1108127987556
|
||||
F ext/fts5/tool/mkfts5c.tcl 5745072c7de346e18c7f491e4c3281fe8a1cfe51
|
||||
F ext/fts5/tool/showfts5.tcl fb62e8eae6d862afdd22f367e286fb886d5e1ab6
|
||||
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c b2732aef0b076e4276d9b39b5a33cec7a05e1413
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
@ -204,7 +204,7 @@ F ext/ota/ota.c 3a849c3b0a4ad6e63125668be9f67be03621216e
|
||||
F ext/ota/ota1.test abdcbe746db4c7f7b51e842b576cacb33eef28f5
|
||||
F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
|
||||
F ext/ota/ota11.test 2f606cd2b4af260a86b549e91b9f395450fc75cb
|
||||
F ext/ota/ota12.test 0dff44474de448fb4b0b28c20da63273a4149abb
|
||||
F ext/ota/ota12.test e4c0b9a14255ffbe04d241fc15da2c65b3c06846
|
||||
F ext/ota/ota13.test f7a3d73fa5d3fabf2755b569f125fce7390a874c
|
||||
F ext/ota/ota3.test 3fe3521fbdce32d0e4e116a60999c3cba47712c5
|
||||
F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
|
||||
@ -267,7 +267,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 574470491635f477235a16df7bd80e1a22a9a282
|
||||
F main.mk c4250d110d0275a9903f12788346f1dc795275bf
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@ -288,7 +288,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452
|
||||
F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d
|
||||
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
|
||||
F src/btree.c cf3375bf706d15d3b8b7ac1fc86b0bf5603324d5
|
||||
F src/btree.c 781deff0d5af639e8dd4f83ec963cc3bbf8cffc2
|
||||
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
|
||||
F src/btreeInt.h 2ad754dd4528baa8d0946a593cc373b890bf859e
|
||||
F src/build.c b3f15255d5b16e42dafeaa638fd4f8a47c94ed70
|
||||
@ -302,7 +302,7 @@ F src/expr.c c5c58e4d01c7ceb2266791d8d877f1b23a88e316
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c c9b63a217d86582c22121699a47f22f524608869
|
||||
F src/func.c a98ea5880dc50e9ca6dd6f57079a37b9cfcdecf1
|
||||
F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e
|
||||
F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
@ -312,7 +312,7 @@ F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712
|
||||
F src/loadext.c e722f4b832f923744788365df5fb8515c0bc8a47
|
||||
F src/main.c 5e170f7c4872c272d733572a99628e47fe92ab43
|
||||
F src/malloc.c 9be4e645f2fb411e5a04cf97e91f68b4faa6dc81
|
||||
F src/malloc.c 19461e159bccf0e2cf06a50e867963d0a7b124a8
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
@ -322,23 +322,23 @@ F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
|
||||
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
|
||||
F src/mutex.c 529e95739f815300a33c73fd8a7d6bdf0c24bd18
|
||||
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
|
||||
F src/mutex_noop.c 529bab0743c3321c940f32c3464de494fd38cfa9
|
||||
F src/mutex_unix.c 5cf676464bd19e0a866297515d146e8bf1669dfb
|
||||
F src/mutex_w32.c 61660ada28d8308ad190f444c2170c4f2a590c2f
|
||||
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
|
||||
F src/mutex_unix.c b0d280089df0f49545f1318f45d61d07d2f674a8
|
||||
F src/mutex_w32.c b601f9e3073f7bd2c1f42a8c0ce59e42d6a08f85
|
||||
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
|
||||
F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
F src/os_common.h abdb9a191a367793268fe553d25bab894e986a0e
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c 23eb5f56fac54d8fe0cb204291f3b3b2d94f23fc
|
||||
F src/os_win.c 27cc135e2d0b8b1e2e4944db1e2669a6a18fa0f8
|
||||
F src/os_unix.c 388c023582b17890f10c980b30ec1922b471753b
|
||||
F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a
|
||||
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
|
||||
F src/pager.c aa916ca28606ccf4b6877dfc2b643ccbca86589f
|
||||
F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2
|
||||
F src/parse.y 6d60dda8f8d418b6dc034f1fbccd816c459983a8
|
||||
F src/pcache.c cde06aa50962595e412d497e22fd2e07878ba1f0
|
||||
F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9
|
||||
F src/pcache1.c 9ec20f98f50ed7415019303ae9bd3745d4b7bd9b
|
||||
F src/pcache1.c 3f4c87cf913f2de8189026d9a5223ddaf55eaf6b
|
||||
F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7
|
||||
F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc
|
||||
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
|
||||
@ -346,12 +346,12 @@ F src/printf.c db11b5960105ee661dcac690f2ae6276e49bf251
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c 2d47554370de8de6dd5be060cef9559eec315005
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c 7003fe663bc0636b656874440845a85dcbad4ba7
|
||||
F src/select.c d3c04f01549317afbe02455c4ca9465100e9c5fe
|
||||
F src/shell.c e4ad9031072a6d679b2c69a780014d30db62dc7f
|
||||
F src/sqlite.h.in 876ad21b9a6bb5034db7c44cdebd5df2292a5336
|
||||
F src/sqlite.h.in 84aac470adebde08e319c200f892664c6e976692
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h be1a718b7d2ce40ceba725ae92c8eb5f18003066
|
||||
F src/sqliteInt.h b408931086cdcebb6d70c3561b7fe18efb2d48c9
|
||||
F src/sqliteInt.h f5d9aa5d0cb0c89af4030c5b5b0ff93d5ef1e9a3
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
|
||||
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
|
||||
@ -384,7 +384,7 @@ F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
|
||||
F src/test_malloc.c 208f09a4e21defa496bc1094fcfadea19385a112
|
||||
F src/test_multiplex.c 9fefd23f6cc3fa9bf0748a5e453167e7b9f193ce
|
||||
F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
F src/test_mutex.c dbdfaff8580071f2212a0deae3325a93a737819c
|
||||
F src/test_onefile.c 38f7cbe79d5bafe95bde683cc3a53b8ca16daf10
|
||||
F src/test_osinst.c 5423dc1d355f594371f27dd292ca54bd320b8196
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
@ -407,13 +407,13 @@ F src/treeview.c c84b1a8ebc7f1d00cd76ce4958eeb3ae1021beed
|
||||
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
|
||||
F src/update.c 24dd6a45b8b3470e62702128ebf11be1f2693145
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c 075c2878fb698bd387164047ecdf76f6cbacf402
|
||||
F src/util.c 46358a204b35971a839341cf64599d65b151ba88
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 195b32310c7062847a45fda214b32ceb8f8f6ab2
|
||||
F src/vdbe.h d0f8ab919146109d080cde4b0840af9b5fafad4b
|
||||
F src/vdbeInt.h 963c87c4bf8040c0a316ca3e58f8a4888e1fa3c4
|
||||
F src/vdbeapi.c a5d2e8afd53b4f81934f5ca59c04465cd1a6d50d
|
||||
F src/vdbeaux.c d6bfb7b4291bc033283140e21c2da2ce04ef0f78
|
||||
F src/vdbeapi.c 86f01f72f8341c0394ff745e68962b17bfb0974e
|
||||
F src/vdbeaux.c 2d86fc5411e4e659c9181ef642c63dff602b3684
|
||||
F src/vdbeblob.c ab33f9b57cfce7dddb23853090186da614be4846
|
||||
F src/vdbemem.c 6c9e261d135fc175da2f34e46d60243a19fffb9f
|
||||
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
|
||||
@ -710,13 +710,14 @@ F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3expr3.test 9e91b8edbcb197bf2e92161aa7696446d96dce5f
|
||||
F test/fts3expr4.test e1be1248566f43c252d4404d52914f1fc4bfa065
|
||||
F test/fts3expr5.test f9abfffbf5e53d48a33e12a1e8f8ba2c551c9b49
|
||||
F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
|
||||
F test/fts3fault.test da49627b280b210ebc6657f76344c7851f10ce66
|
||||
F test/fts3fault2.test f953bb3cf903988172270a9a0aafd5a890b0f98f
|
||||
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
|
||||
F test/fts3join.test 53e66a0c21eb568580674a43b21c059acb26f499
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test 07009313ad6c082f94d8c9c3228eb8940c93ac71
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3offsets.test 5b8ec5be27dd2070af3538b23c67f1ca8c822853
|
||||
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
|
||||
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
|
||||
F test/fts3query.test f33eb71a1fe1084ea585eeb7ee76b390729f5170
|
||||
@ -862,9 +863,9 @@ F test/mallocL.test 252ddc7eb4fbf75364eab17b938816085ff1fc17
|
||||
F test/malloc_common.tcl aac62499b76be719fac31e7a3e54a7fd53272e7f
|
||||
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test fcb5297b321b562084fc79d64d5a12a1cd2b639b
|
||||
F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 690d142525a7d31efb638b0d232e25fac3afeb1a
|
||||
F test/memsubsys1.test 1733c617e246642db5bf3b9f78c18e2b14fac96c
|
||||
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
|
||||
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
@ -887,7 +888,7 @@ F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
|
||||
F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
F test/mutex1.test e0a44072d98189003deae4b091106f085d94bea8
|
||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||
F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
F test/nolock.test 0540dd96f39b8876e3ffdd8814fad0ea425efeee
|
||||
@ -919,7 +920,7 @@ F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8
|
||||
F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6
|
||||
F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/pcache2.test ec3ae192f444ee6a0a80d1fd80d99695d884bfb3
|
||||
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
|
||||
F test/permutations.test 1a49f543ec7f0e075ca24eae3bda7f75bb00634b
|
||||
F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2
|
||||
@ -1025,7 +1026,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c a2834483e435cf6017b0fead53c5a68c6efc67e8
|
||||
F test/speedtest1.c 54f211994e2fb5b3f7c5c82137378f46ca89aae8
|
||||
F test/spellfix.test 0597065ff57042df1f138e6a2611ae19c2698135
|
||||
F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5
|
||||
F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68
|
||||
@ -1202,7 +1203,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
|
||||
F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0
|
||||
F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
|
||||
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
@ -1316,7 +1317,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test e99845d4f4bf7863b61f104de554c61739d65764
|
||||
F test/with1.test a1e8660be88e2eb4648f8860f831d1e38b5b5443
|
||||
F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test 1a7b9bd51b899928d327052df9741d2fe8dbe701
|
||||
@ -1341,7 +1342,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
|
||||
F tool/lemon.c b9109f59b57e7b6f101c4fe644c8361ba6dee969
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/loadfts.c 76b6589ab5efcdc9cfe16d43ab5a6c2618e44bd4
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
|
||||
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
|
||||
F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
|
||||
@ -1384,7 +1385,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 39936b33b0668aad81aa574d4d74c92b0ddd218a bcc8a75509aafda61feb6dcc074668c79611a662
|
||||
R e09654bed267c32e59df855cf5a22b97
|
||||
P 85ca4409bdca7aee801e9fba1c49a87fabbf2064 202479aa0a62067343e724487960b8a039e2e978
|
||||
R 582a57d0946e0ad5287c5fb6b7d3efee
|
||||
U drh
|
||||
Z 52c48858632936f2e97d9ccb5e52e5d7
|
||||
Z a3ed5c85e5c2e63374f7522fd856797b
|
||||
|
@ -1 +1 @@
|
||||
85ca4409bdca7aee801e9fba1c49a87fabbf2064
|
||||
db4cbefb8674c6cfff27c1e918741de1885c845c
|
25
src/btree.c
25
src/btree.c
@ -8955,10 +8955,11 @@ static int checkTreePage(
|
||||
u32 usableSize; /* Usable size of the page */
|
||||
u32 contentOffset; /* Offset to the start of the cell content area */
|
||||
u32 *heap = 0; /* Min-heap used for checking cell coverage */
|
||||
u32 x, prev = 0;
|
||||
u32 x, prev = 0; /* Next and previous entry on the min-heap */
|
||||
const char *saved_zPfx = pCheck->zPfx;
|
||||
int saved_v1 = pCheck->v1;
|
||||
int saved_v2 = pCheck->v2;
|
||||
u8 savedIsInit;
|
||||
|
||||
/* Check that the page exists
|
||||
*/
|
||||
@ -8976,6 +8977,7 @@ static int checkTreePage(
|
||||
|
||||
/* Clear MemPage.isInit to make sure the corruption detection code in
|
||||
** btreeInitPage() is executed. */
|
||||
savedIsInit = pPage->isInit;
|
||||
pPage->isInit = 0;
|
||||
if( (rc = btreeInitPage(pPage))!=0 ){
|
||||
assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */
|
||||
@ -9018,7 +9020,6 @@ static int checkTreePage(
|
||||
** as the other cell checks, so initialize the heap. */
|
||||
heap = pCheck->heap;
|
||||
heap[0] = 0;
|
||||
btreeHeapInsert(heap, contentOffset-1);
|
||||
}
|
||||
|
||||
/* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
|
||||
@ -9099,7 +9100,6 @@ static int checkTreePage(
|
||||
if( !pPage->leaf ){
|
||||
heap = pCheck->heap;
|
||||
heap[0] = 0;
|
||||
btreeHeapInsert(heap, contentOffset-1);
|
||||
for(i=nCell-1; i>=0; i--){
|
||||
u32 size;
|
||||
pc = get2byteAligned(&data[cellStart+i*2]);
|
||||
@ -9119,7 +9119,7 @@ static int checkTreePage(
|
||||
assert( (u32)i<=usableSize-4 ); /* Enforced by btreeInitPage() */
|
||||
size = get2byte(&data[i+2]);
|
||||
assert( (u32)(i+size)<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
btreeHeapInsert(heap, (i<<16)|(i+size-1));
|
||||
btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1));
|
||||
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
|
||||
** big-endian integer which is the offset in the b-tree page of the next
|
||||
** freeblock in the chain, or zero if the freeblock is the last on the
|
||||
@ -9133,13 +9133,21 @@ static int checkTreePage(
|
||||
}
|
||||
/* Analyze the min-heap looking for overlap between cells and/or
|
||||
** freeblocks, and counting the number of untracked bytes in nFrag.
|
||||
**
|
||||
** Each min-heap entry is of the form: (start_address<<16)|end_address.
|
||||
** There is an implied first entry the covers the page header, the cell
|
||||
** pointer index, and the gap between the cell pointer index and the start
|
||||
** of cell content.
|
||||
**
|
||||
** The loop below pulls entries from the min-heap in order and compares
|
||||
** the start_address against the previous end_address. If there is an
|
||||
** overlap, that means bytes are used multiple times. If there is a gap,
|
||||
** that gap is added to the fragmentation count.
|
||||
*/
|
||||
nFrag = 0;
|
||||
assert( heap[0]>0 );
|
||||
assert( (heap[1]>>16)==0 );
|
||||
btreeHeapPull(heap,&prev);
|
||||
prev = contentOffset - 1; /* Implied first min-heap entry */
|
||||
while( btreeHeapPull(heap,&x) ){
|
||||
if( (prev&0xffff)+1>(x>>16) ){
|
||||
if( (prev&0xffff)>=(x>>16) ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Multiple uses for byte %u of page %d", x>>16, iPage);
|
||||
break;
|
||||
@ -9162,6 +9170,7 @@ static int checkTreePage(
|
||||
}
|
||||
|
||||
end_of_check:
|
||||
if( !doCoverageCheck ) pPage->isInit = savedIsInit;
|
||||
releasePage(pPage);
|
||||
pCheck->zPfx = saved_zPfx;
|
||||
pCheck->v1 = saved_v1;
|
||||
|
@ -186,7 +186,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
0, /* nScratch */
|
||||
(void*)0, /* pPage */
|
||||
0, /* szPage */
|
||||
0, /* nPage */
|
||||
SQLITE_DEFAULT_PCACHE_INITSZ, /* nPage */
|
||||
0, /* mxParserStack */
|
||||
0, /* sharedCacheEnabled */
|
||||
SQLITE_SORTER_PMASZ, /* szPma */
|
||||
|
@ -193,10 +193,9 @@ int sqlite3MallocInit(void){
|
||||
sqlite3GlobalConfig.nScratch = 0;
|
||||
}
|
||||
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|
||||
|| sqlite3GlobalConfig.nPage<1 ){
|
||||
|| sqlite3GlobalConfig.nPage<=0 ){
|
||||
sqlite3GlobalConfig.pPage = 0;
|
||||
sqlite3GlobalConfig.szPage = 0;
|
||||
sqlite3GlobalConfig.nPage = 0;
|
||||
}
|
||||
rc = sqlite3GlobalConfig.m.xInit(sqlite3GlobalConfig.m.pAppData);
|
||||
if( rc!=SQLITE_OK ) memset(&mem0, 0, sizeof(mem0));
|
||||
|
@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
|
||||
** that means that a mutex could not be allocated.
|
||||
*/
|
||||
static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
|
||||
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
|
||||
sqlite3_debug_mutex *pNew = 0;
|
||||
switch( id ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
|
@ -105,6 +105,9 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** <li> SQLITE_MUTEX_STATIC_APP3
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS1
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS2
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS3
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
@ -141,6 +144,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
|
@ -89,6 +89,9 @@ static sqlite3_mutex winMutex_staticMutexes[] = {
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER
|
||||
};
|
||||
|
||||
@ -160,6 +163,9 @@ static int winMutexEnd(void){
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** <li> SQLITE_MUTEX_STATIC_APP3
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS1
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS2
|
||||
** <li> SQLITE_MUTEX_STATIC_VFS3
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
|
@ -629,14 +629,14 @@ static int robust_open(const char *z, int f, mode_t m){
|
||||
** unixEnterLeave()
|
||||
*/
|
||||
static void unixEnterMutex(void){
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
static void unixLeaveMutex(void){
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
static int unixMutexHeld(void) {
|
||||
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3390,14 +3390,14 @@ static SYSTEM_INFO winSysInfo;
|
||||
** winShmLeaveMutex()
|
||||
*/
|
||||
static void winShmEnterMutex(void){
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
static void winShmLeaveMutex(void){
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
static int winShmMutexHeld(void) {
|
||||
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
||||
return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
265
src/pcache1.c
265
src/pcache1.c
@ -15,8 +15,71 @@
|
||||
** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features.
|
||||
** If the default page cache implementation is overridden, then neither of
|
||||
** these two features are available.
|
||||
**
|
||||
** A Page cache line looks like this:
|
||||
**
|
||||
** -------------------------------------------------------------
|
||||
** | database page content | PgHdr1 | MemPage | PgHdr |
|
||||
** -------------------------------------------------------------
|
||||
**
|
||||
** The database page content is up front (so that buffer overreads tend to
|
||||
** flow harmlessly into the PgHdr1, MemPage, and PgHdr extensions). MemPage
|
||||
** is the extension added by the btree.c module containing information such
|
||||
** as the database page number and how that database page is used. PgHdr
|
||||
** is added by the pcache.c layer and contains information used to keep track
|
||||
** of which pages are "dirty". PgHdr1 is an extension added by this
|
||||
** module (pcache1.c). The PgHdr1 header is a subclass of sqlite3_pcache_page.
|
||||
** PgHdr1 contains information needed to look up a page by its page number.
|
||||
** The superclass sqlite3_pcache_page.pBuf points to the start of the
|
||||
** database page content and sqlite3_pcache_page.pExtra points to PgHdr.
|
||||
**
|
||||
** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at
|
||||
** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The
|
||||
** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this
|
||||
** size can vary according to architecture, compile-time options, and
|
||||
** SQLite library version number.
|
||||
**
|
||||
** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
|
||||
** using a separate memory allocation from the database page content. This
|
||||
** seeks to overcome the "clownshoe" problem (also called "internal
|
||||
** fragmentation" in academic literature) of allocating a few bytes more
|
||||
** than a power of two with the memory allocator rounding up to the next
|
||||
** power of two, and leaving the rounded-up space unused.
|
||||
**
|
||||
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
|
||||
** with this module. Information is passed back and forth as PgHdr1 pointers.
|
||||
**
|
||||
** The pcache.c and pager.c modules deal pointers to PgHdr objects.
|
||||
** The btree.c module deals with pointers to MemPage objects.
|
||||
**
|
||||
** SOURCE OF PAGE CACHE MEMORY:
|
||||
**
|
||||
** Memory for a page might come from any of three sources:
|
||||
**
|
||||
** (1) The general-purpose memory allocator - sqlite3Malloc()
|
||||
** (2) Global page-cache memory provided using sqlite3_config() with
|
||||
** SQLITE_CONFIG_PAGECACHE.
|
||||
** (3) PCache-local bulk allocation.
|
||||
**
|
||||
** The third case is a chunk of heap memory (defaulting to 100 pages worth)
|
||||
** that is allocated when the page cache is created. The size of the local
|
||||
** bulk allocation can be adjusted using
|
||||
**
|
||||
** sqlite3_config(SQLITE_CONFIG_PCACHE, 0, 0, N).
|
||||
**
|
||||
** If N is positive, then N pages worth of memory are allocated using a single
|
||||
** sqlite3Malloc() call and that memory is used for the first N pages allocated.
|
||||
** Or if N is negative, then -1024*N bytes of memory are allocated and used
|
||||
** for as many pages as can be accomodated.
|
||||
**
|
||||
** Only one of (2) or (3) can be used. Once the memory available to (2) or
|
||||
** (3) is exhausted, subsequent allocations fail over to the general-purpose
|
||||
** memory allocator (1).
|
||||
**
|
||||
** Earlier versions of SQLite used only methods (1) and (2). But experiments
|
||||
** show that method (3) with N==100 provides about a 5% performance boost for
|
||||
** common workloads.
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
|
||||
typedef struct PCache1 PCache1;
|
||||
@ -70,8 +133,9 @@ struct PCache1 {
|
||||
** The PGroup mutex must be held when accessing nMax.
|
||||
*/
|
||||
PGroup *pGroup; /* PGroup this cache belongs to */
|
||||
int szPage; /* Size of allocated pages in bytes */
|
||||
int szExtra; /* Size of extra space in bytes */
|
||||
int szPage; /* Size of database content section */
|
||||
int szExtra; /* sizeof(MemPage)+sizeof(PgHdr) */
|
||||
int szAlloc; /* Total size of one pcache line */
|
||||
int bPurgeable; /* True if cache is purgeable */
|
||||
unsigned int nMin; /* Minimum number of pages reserved */
|
||||
unsigned int nMax; /* Configured "cache_size" value */
|
||||
@ -85,6 +149,8 @@ struct PCache1 {
|
||||
unsigned int nPage; /* Total number of pages in apHash */
|
||||
unsigned int nHash; /* Number of slots in apHash[] */
|
||||
PgHdr1 **apHash; /* Hash table for fast lookup by key */
|
||||
PgHdr1 *pFree; /* List of unused pcache-local pages */
|
||||
void *pBulk; /* Bulk memory used by pcache-local */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -97,6 +163,7 @@ struct PgHdr1 {
|
||||
sqlite3_pcache_page page;
|
||||
unsigned int iKey; /* Key value (page number) */
|
||||
u8 isPinned; /* Page in use, not on the LRU list */
|
||||
u8 isBulkLocal; /* This page from bulk local storage */
|
||||
PgHdr1 *pNext; /* Next in hash table chain */
|
||||
PCache1 *pCache; /* Cache that currently owns this page */
|
||||
PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
|
||||
@ -104,8 +171,8 @@ struct PgHdr1 {
|
||||
};
|
||||
|
||||
/*
|
||||
** Free slots in the allocator used to divide up the buffer provided using
|
||||
** the SQLITE_CONFIG_PAGECACHE mechanism.
|
||||
** Free slots in the allocator used to divide up the global page cache
|
||||
** buffer provided using the SQLITE_CONFIG_PAGECACHE mechanism.
|
||||
*/
|
||||
struct PgFreeslot {
|
||||
PgFreeslot *pNext; /* Next free slot */
|
||||
@ -123,10 +190,11 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
** The nFreeSlot and pFree values do require mutex protection.
|
||||
*/
|
||||
int isInit; /* True if initialized */
|
||||
int separateCache; /* Use a new PGroup for each PCache */
|
||||
int szSlot; /* Size of each free slot */
|
||||
int nSlot; /* The number of pcache slots */
|
||||
int nReserve; /* Try to keep nFreeSlot above this */
|
||||
void *pStart, *pEnd; /* Bounds of pagecache malloc range */
|
||||
void *pStart, *pEnd; /* Bounds of global page cache memory */
|
||||
/* Above requires no mutex. Use mutex below for variable that follow. */
|
||||
sqlite3_mutex *mutex; /* Mutex for accessing the following: */
|
||||
PgFreeslot *pFree; /* Free page blocks */
|
||||
@ -173,6 +241,7 @@ static SQLITE_WSD struct PCacheGlobal {
|
||||
void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
|
||||
if( pcache1.isInit ){
|
||||
PgFreeslot *p;
|
||||
if( pBuf==0 ) sz = n = 0;
|
||||
sz = ROUNDDOWN8(sz);
|
||||
pcache1.szSlot = sz;
|
||||
pcache1.nSlot = pcache1.nFreeSlot = n;
|
||||
@ -237,9 +306,9 @@ static void *pcache1Alloc(int nByte){
|
||||
/*
|
||||
** Free an allocated buffer obtained from pcache1Alloc().
|
||||
*/
|
||||
static int pcache1Free(void *p){
|
||||
static void pcache1Free(void *p){
|
||||
int nFreed = 0;
|
||||
if( p==0 ) return 0;
|
||||
if( p==0 ) return;
|
||||
if( p>=pcache1.pStart && p<pcache1.pEnd ){
|
||||
PgFreeslot *pSlot;
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
@ -254,15 +323,14 @@ static int pcache1Free(void *p){
|
||||
}else{
|
||||
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
|
||||
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
||||
nFreed = sqlite3MallocSize(p);
|
||||
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
|
||||
nFreed = sqlite3MallocSize(p);
|
||||
sqlite3_mutex_enter(pcache1.mutex);
|
||||
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_OVERFLOW, nFreed);
|
||||
sqlite3_mutex_leave(pcache1.mutex);
|
||||
#endif
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return nFreed;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
@ -290,54 +358,65 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache){
|
||||
PgHdr1 *p = 0;
|
||||
void *pPg;
|
||||
|
||||
/* The group mutex must be released before pcache1Alloc() is called. This
|
||||
** is because it may call sqlite3_release_memory(), which assumes that
|
||||
** this mutex is not held. */
|
||||
assert( sqlite3_mutex_held(pCache->pGroup->mutex) );
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
pPg = pcache1Alloc(pCache->szPage);
|
||||
p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
|
||||
if( !pPg || !p ){
|
||||
pcache1Free(pPg);
|
||||
sqlite3_free(p);
|
||||
pPg = 0;
|
||||
}
|
||||
#else
|
||||
pPg = pcache1Alloc(ROUND8(sizeof(PgHdr1)) + pCache->szPage + pCache->szExtra);
|
||||
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
|
||||
if( pCache->pFree ){
|
||||
p = pCache->pFree;
|
||||
pCache->pFree = p->pNext;
|
||||
p->pNext = 0;
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
/* The group mutex must be released before pcache1Alloc() is called. This
|
||||
** is because it might call sqlite3_release_memory(), which assumes that
|
||||
** this mutex is not held. */
|
||||
assert( pcache1.separateCache==0 );
|
||||
assert( pCache->pGroup==&pcache1.grp );
|
||||
pcache1LeaveMutex(pCache->pGroup);
|
||||
#endif
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
|
||||
if( pPg ){
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
pPg = pcache1Alloc(pCache->szPage);
|
||||
p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
|
||||
if( !pPg || !p ){
|
||||
pcache1Free(pPg);
|
||||
sqlite3_free(p);
|
||||
pPg = 0;
|
||||
}
|
||||
#else
|
||||
pPg = pcache1Alloc(pCache->szAlloc);
|
||||
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
pcache1EnterMutex(pCache->pGroup);
|
||||
#endif
|
||||
if( pPg==0 ) return 0;
|
||||
p->page.pBuf = pPg;
|
||||
p->page.pExtra = &p[1];
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage++;
|
||||
}
|
||||
return p;
|
||||
p->isBulkLocal = 0;
|
||||
}
|
||||
return 0;
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a page object allocated by pcache1AllocPage().
|
||||
**
|
||||
** The pointer is allowed to be NULL, which is prudent. But it turns out
|
||||
** that the current implementation happens to never call this routine
|
||||
** with a NULL pointer, so we mark the NULL test with ALWAYS().
|
||||
*/
|
||||
static void pcache1FreePage(PgHdr1 *p){
|
||||
if( ALWAYS(p) ){
|
||||
PCache1 *pCache = p->pCache;
|
||||
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
|
||||
PCache1 *pCache;
|
||||
assert( p!=0 );
|
||||
pCache = p->pCache;
|
||||
assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) );
|
||||
if( p->isBulkLocal ){
|
||||
p->pNext = pCache->pFree;
|
||||
pCache->pFree = p;
|
||||
}else{
|
||||
pcache1Free(p->page.pBuf);
|
||||
#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
||||
sqlite3_free(p);
|
||||
#endif
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage--;
|
||||
}
|
||||
}
|
||||
if( pCache->bPurgeable ){
|
||||
pCache->pGroup->nCurrentPage--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,6 +616,31 @@ static int pcache1Init(void *NotUsed){
|
||||
UNUSED_PARAMETER(NotUsed);
|
||||
assert( pcache1.isInit==0 );
|
||||
memset(&pcache1, 0, sizeof(pcache1));
|
||||
|
||||
|
||||
/*
|
||||
** The pcache1.separateCache variable is true if each PCache has its own
|
||||
** private PGroup (mode-1). pcache1.separateCache is false if the single
|
||||
** PGroup in pcache1.grp is used for all page caches (mode-2).
|
||||
**
|
||||
** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
|
||||
**
|
||||
** * Use a unified cache in single-threaded applications that have
|
||||
** configured a start-time buffer for use as page-cache memory using
|
||||
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
|
||||
** pBuf argument.
|
||||
**
|
||||
** * Otherwise use separate caches (mode-1)
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT)
|
||||
pcache1.separateCache = 0;
|
||||
#elif SQLITE_THREADSAFE
|
||||
pcache1.separateCache = sqlite3GlobalConfig.pPage==0
|
||||
|| sqlite3GlobalConfig.bCoreMutex>0;
|
||||
#else
|
||||
pcache1.separateCache = sqlite3GlobalConfig.pPage==0;
|
||||
#endif
|
||||
|
||||
#if SQLITE_THREADSAFE
|
||||
if( sqlite3GlobalConfig.bCoreMutex ){
|
||||
pcache1.grp.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_LRU);
|
||||
@ -572,31 +676,13 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
||||
PGroup *pGroup; /* The group the new page cache will belong to */
|
||||
int sz; /* Bytes of memory required to allocate the new cache */
|
||||
|
||||
/*
|
||||
** The separateCache variable is true if each PCache has its own private
|
||||
** PGroup. In other words, separateCache is true for mode (1) where no
|
||||
** mutexing is required.
|
||||
**
|
||||
** * Always use a unified cache (mode-2) if ENABLE_MEMORY_MANAGEMENT
|
||||
**
|
||||
** * Always use a unified cache in single-threaded applications
|
||||
**
|
||||
** * Otherwise (if multi-threaded and ENABLE_MEMORY_MANAGEMENT is off)
|
||||
** use separate caches (mode-1)
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) || SQLITE_THREADSAFE==0
|
||||
const int separateCache = 0;
|
||||
#else
|
||||
int separateCache = sqlite3GlobalConfig.bCoreMutex>0;
|
||||
#endif
|
||||
|
||||
assert( (szPage & (szPage-1))==0 && szPage>=512 && szPage<=65536 );
|
||||
assert( szExtra < 300 );
|
||||
|
||||
sz = sizeof(PCache1) + sizeof(PGroup)*separateCache;
|
||||
sz = sizeof(PCache1) + sizeof(PGroup)*pcache1.separateCache;
|
||||
pCache = (PCache1 *)sqlite3MallocZero(sz);
|
||||
if( pCache ){
|
||||
if( separateCache ){
|
||||
if( pcache1.separateCache ){
|
||||
pGroup = (PGroup*)&pCache[1];
|
||||
pGroup->mxPinned = 10;
|
||||
}else{
|
||||
@ -605,6 +691,7 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
||||
pCache->pGroup = pGroup;
|
||||
pCache->szPage = szPage;
|
||||
pCache->szExtra = szExtra;
|
||||
pCache->szAlloc = szPage + szExtra + ROUND8(sizeof(PgHdr1));
|
||||
pCache->bPurgeable = (bPurgeable ? 1 : 0);
|
||||
pcache1EnterMutex(pGroup);
|
||||
pcache1ResizeHash(pCache);
|
||||
@ -614,6 +701,36 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
||||
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
||||
}
|
||||
pcache1LeaveMutex(pGroup);
|
||||
/* Try to initialize the local bulk pagecache line allocation if using
|
||||
** separate caches and if nPage!=0 */
|
||||
if( pcache1.separateCache
|
||||
&& sqlite3GlobalConfig.nPage!=0
|
||||
&& sqlite3GlobalConfig.pPage==0
|
||||
){
|
||||
int szBulk;
|
||||
char *zBulk;
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( sqlite3GlobalConfig.nPage>0 ){
|
||||
szBulk = pCache->szAlloc * sqlite3GlobalConfig.nPage;
|
||||
}else{
|
||||
szBulk = -1024*sqlite3GlobalConfig.nPage;
|
||||
}
|
||||
zBulk = pCache->pBulk = sqlite3Malloc( szBulk );
|
||||
sqlite3EndBenignMalloc();
|
||||
if( zBulk ){
|
||||
int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc;
|
||||
int i;
|
||||
for(i=0; i<nBulk; i++){
|
||||
PgHdr1 *pX = (PgHdr1*)&zBulk[szPage];
|
||||
pX->page.pBuf = zBulk;
|
||||
pX->page.pExtra = &pX[1];
|
||||
pX->isBulkLocal = 1;
|
||||
pX->pNext = pCache->pFree;
|
||||
pCache->pFree = pX;
|
||||
zBulk += pCache->szAlloc;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pCache->nHash==0 ){
|
||||
pcache1Destroy((sqlite3_pcache*)pCache);
|
||||
pCache = 0;
|
||||
@ -707,26 +824,17 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
||||
assert( pCache->nHash>0 && pCache->apHash );
|
||||
|
||||
/* Step 4. Try to recycle a page. */
|
||||
if( pCache->bPurgeable && pGroup->pLruTail && (
|
||||
(pCache->nPage+1>=pCache->nMax)
|
||||
|| pGroup->nCurrentPage>=pGroup->nMaxPage
|
||||
|| pcache1UnderMemoryPressure(pCache)
|
||||
)){
|
||||
if( pCache->bPurgeable
|
||||
&& pGroup->pLruTail
|
||||
&& ((pCache->nPage+1>=pCache->nMax) || pcache1UnderMemoryPressure(pCache))
|
||||
){
|
||||
PCache1 *pOther;
|
||||
pPage = pGroup->pLruTail;
|
||||
assert( pPage->isPinned==0 );
|
||||
pcache1RemoveFromHash(pPage, 0);
|
||||
pcache1PinPage(pPage);
|
||||
pOther = pPage->pCache;
|
||||
|
||||
/* We want to verify that szPage and szExtra are the same for pOther
|
||||
** and pCache. Assert that we can verify this by comparing sums. */
|
||||
assert( (pCache->szPage & (pCache->szPage-1))==0 && pCache->szPage>=512 );
|
||||
assert( pCache->szExtra<512 );
|
||||
assert( (pOther->szPage & (pOther->szPage-1))==0 && pOther->szPage>=512 );
|
||||
assert( pOther->szExtra<512 );
|
||||
|
||||
if( pOther->szPage+pOther->szExtra != pCache->szPage+pCache->szExtra ){
|
||||
if( pOther->szAlloc != pCache->szAlloc ){
|
||||
pcache1FreePage(pPage);
|
||||
pPage = 0;
|
||||
}else{
|
||||
@ -1002,6 +1110,7 @@ static void pcache1Destroy(sqlite3_pcache *p){
|
||||
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
||||
pcache1EnforceMaxPage(pGroup);
|
||||
pcache1LeaveMutex(pGroup);
|
||||
sqlite3_free(pCache->pBulk);
|
||||
sqlite3_free(pCache->apHash);
|
||||
sqlite3_free(pCache);
|
||||
}
|
||||
@ -1057,7 +1166,7 @@ int sqlite3PcacheReleaseMemory(int nReq){
|
||||
int nFree = 0;
|
||||
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
|
||||
assert( sqlite3_mutex_notheld(pcache1.mutex) );
|
||||
if( pcache1.pStart==0 ){
|
||||
if( sqlite3GlobalConfig.nPage==0 ){
|
||||
PgHdr1 *p;
|
||||
pcache1EnterMutex(&pcache1.grp);
|
||||
while( (nReq<0 || nFree<nReq) && ((p=pcache1.grp.pLruTail)!=0) ){
|
||||
|
12
src/select.c
12
src/select.c
@ -2070,10 +2070,14 @@ static void generateWithRecursiveQuery(
|
||||
/* Execute the recursive SELECT taking the single row in Current as
|
||||
** the value for the recursive-table. Store the results in the Queue.
|
||||
*/
|
||||
p->pPrior = 0;
|
||||
sqlite3Select(pParse, p, &destQueue);
|
||||
assert( p->pPrior==0 );
|
||||
p->pPrior = pSetup;
|
||||
if( p->selFlags & SF_Aggregate ){
|
||||
sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
|
||||
}else{
|
||||
p->pPrior = 0;
|
||||
sqlite3Select(pParse, p, &destQueue);
|
||||
assert( p->pPrior==0 );
|
||||
p->pPrior = pSetup;
|
||||
}
|
||||
|
||||
/* Keep running the loop until the Queue is empty */
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||
|
@ -6291,6 +6291,9 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_VFS1 11 /* For use by built-in VFS */
|
||||
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
|
||||
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
|
@ -509,6 +509,16 @@
|
||||
# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The default initial allocation for the pagecache when using separate
|
||||
** pagecaches for each database connection. A positive number is the
|
||||
** number of pages. A negative number N translations means that a buffer
|
||||
** of -1024*N bytes is allocated and used for as many pages as it will hold.
|
||||
*/
|
||||
#ifndef SQLITE_DEFAULT_PCACHE_INITSZ
|
||||
# define SQLITE_DEFAULT_PCACHE_INITSZ 100
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** GCC does not define the offsetof() macro so we'll have to do it
|
||||
|
@ -19,9 +19,19 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_MUTEXES (SQLITE_MUTEX_STATIC_VFS3+1)
|
||||
#define STATIC_MUTEXES (MAX_MUTEXES-(SQLITE_MUTEX_RECURSIVE+1))
|
||||
|
||||
/* defined in main.c */
|
||||
extern const char *sqlite3ErrName(int);
|
||||
|
||||
static const char *aName[MAX_MUTEXES+1] = {
|
||||
"fast", "recursive", "static_master", "static_mem",
|
||||
"static_open", "static_prng", "static_lru", "static_pmem",
|
||||
"static_app1", "static_app2", "static_app3", "static_vfs1",
|
||||
"static_vfs2", "static_vfs3", 0
|
||||
};
|
||||
|
||||
/* A countable mutex */
|
||||
struct sqlite3_mutex {
|
||||
sqlite3_mutex *pReal;
|
||||
@ -30,13 +40,13 @@ struct sqlite3_mutex {
|
||||
|
||||
/* State variables */
|
||||
static struct test_mutex_globals {
|
||||
int isInstalled; /* True if installed */
|
||||
int disableInit; /* True to cause sqlite3_initalize() to fail */
|
||||
int disableTry; /* True to force sqlite3_mutex_try() to fail */
|
||||
int isInit; /* True if initialized */
|
||||
sqlite3_mutex_methods m; /* Interface to "real" mutex system */
|
||||
int aCounter[8]; /* Number of grabs of each type of mutex */
|
||||
sqlite3_mutex aStatic[6]; /* The six static mutexes */
|
||||
int isInstalled; /* True if installed */
|
||||
int disableInit; /* True to cause sqlite3_initalize() to fail */
|
||||
int disableTry; /* True to force sqlite3_mutex_try() to fail */
|
||||
int isInit; /* True if initialized */
|
||||
sqlite3_mutex_methods m; /* Interface to "real" mutex system */
|
||||
int aCounter[MAX_MUTEXES]; /* Number of grabs of each type of mutex */
|
||||
sqlite3_mutex aStatic[STATIC_MUTEXES]; /* The static mutexes */
|
||||
} g = {0};
|
||||
|
||||
/* Return true if the countable mutex is currently held */
|
||||
@ -78,7 +88,8 @@ static sqlite3_mutex *counterMutexAlloc(int eType){
|
||||
sqlite3_mutex *pRet = 0;
|
||||
|
||||
assert( g.isInit );
|
||||
assert(eType<8 && eType>=0);
|
||||
assert( eType>=SQLITE_MUTEX_FAST );
|
||||
assert( eType<=SQLITE_MUTEX_STATIC_VFS3 );
|
||||
|
||||
pReal = g.m.xMutexAlloc(eType);
|
||||
if( !pReal ) return 0;
|
||||
@ -86,7 +97,10 @@ static sqlite3_mutex *counterMutexAlloc(int eType){
|
||||
if( eType==SQLITE_MUTEX_FAST || eType==SQLITE_MUTEX_RECURSIVE ){
|
||||
pRet = (sqlite3_mutex *)malloc(sizeof(sqlite3_mutex));
|
||||
}else{
|
||||
pRet = &g.aStatic[eType-2];
|
||||
int eStaticType = eType - (MAX_MUTEXES - STATIC_MUTEXES);
|
||||
assert( eStaticType>=0 );
|
||||
assert( eStaticType<STATIC_MUTEXES );
|
||||
pRet = &g.aStatic[eStaticType];
|
||||
}
|
||||
|
||||
pRet->eType = eType;
|
||||
@ -110,6 +124,8 @@ static void counterMutexFree(sqlite3_mutex *p){
|
||||
*/
|
||||
static void counterMutexEnter(sqlite3_mutex *p){
|
||||
assert( g.isInit );
|
||||
assert( p->eType>=0 );
|
||||
assert( p->eType<MAX_MUTEXES );
|
||||
g.aCounter[p->eType]++;
|
||||
g.m.xMutexEnter(p->pReal);
|
||||
}
|
||||
@ -119,6 +135,8 @@ static void counterMutexEnter(sqlite3_mutex *p){
|
||||
*/
|
||||
static int counterMutexTry(sqlite3_mutex *p){
|
||||
assert( g.isInit );
|
||||
assert( p->eType>=0 );
|
||||
assert( p->eType<MAX_MUTEXES );
|
||||
g.aCounter[p->eType]++;
|
||||
if( g.disableTry ) return SQLITE_BUSY;
|
||||
return g.m.xMutexTry(p->pReal);
|
||||
@ -245,10 +263,6 @@ static int test_read_mutex_counters(
|
||||
){
|
||||
Tcl_Obj *pRet;
|
||||
int ii;
|
||||
char *aName[8] = {
|
||||
"fast", "recursive", "static_master", "static_mem",
|
||||
"static_open", "static_prng", "static_lru", "static_pmem"
|
||||
};
|
||||
|
||||
if( objc!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "");
|
||||
@ -257,7 +271,7 @@ static int test_read_mutex_counters(
|
||||
|
||||
pRet = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pRet);
|
||||
for(ii=0; ii<8; ii++){
|
||||
for(ii=0; ii<MAX_MUTEXES; ii++){
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(aName[ii], -1));
|
||||
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(g.aCounter[ii]));
|
||||
}
|
||||
@ -283,7 +297,7 @@ static int test_clear_mutex_counters(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
for(ii=0; ii<8; ii++){
|
||||
for(ii=0; ii<MAX_MUTEXES; ii++){
|
||||
g.aCounter[ii] = 0;
|
||||
}
|
||||
return TCL_OK;
|
||||
@ -371,6 +385,56 @@ static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
|
||||
return db;
|
||||
}
|
||||
|
||||
static sqlite3_mutex *getStaticMutexPointer(
|
||||
Tcl_Interp *pInterp,
|
||||
Tcl_Obj *pObj
|
||||
){
|
||||
int iMutex;
|
||||
if( Tcl_GetIndexFromObj(pInterp, pObj, aName, "mutex name", 0, &iMutex) ){
|
||||
return 0;
|
||||
}
|
||||
assert( iMutex!=SQLITE_MUTEX_FAST && iMutex!=SQLITE_MUTEX_RECURSIVE );
|
||||
return counterMutexAlloc(iMutex);
|
||||
}
|
||||
|
||||
static int test_enter_static_mutex(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_mutex *pMutex;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "NAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pMutex = getStaticMutexPointer(interp, objv[1]);
|
||||
if( !pMutex ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_mutex_enter(pMutex);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_leave_static_mutex(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_mutex *pMutex;
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "NAME");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pMutex = getStaticMutexPointer(interp, objv[1]);
|
||||
if( !pMutex ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_mutex_leave(pMutex);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_enter_db_mutex(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
@ -418,6 +482,9 @@ int Sqlitetest_mutex_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_initialize", (Tcl_ObjCmdProc*)test_initialize },
|
||||
{ "sqlite3_config", (Tcl_ObjCmdProc*)test_config },
|
||||
|
||||
{ "enter_static_mutex", (Tcl_ObjCmdProc*)test_enter_static_mutex },
|
||||
{ "leave_static_mutex", (Tcl_ObjCmdProc*)test_leave_static_mutex },
|
||||
|
||||
{ "enter_db_mutex", (Tcl_ObjCmdProc*)test_enter_db_mutex },
|
||||
{ "leave_db_mutex", (Tcl_ObjCmdProc*)test_leave_db_mutex },
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ u32 sqlite3Get4byte(const u8 *p){
|
||||
u32 x;
|
||||
memcpy(&x,p,4);
|
||||
return x;
|
||||
#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__)
|
||||
#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
|
||||
u32 x;
|
||||
memcpy(&x,p,4);
|
||||
return __builtin_bswap32(x);
|
||||
@ -1098,7 +1098,7 @@ u32 sqlite3Get4byte(const u8 *p){
|
||||
void sqlite3Put4byte(unsigned char *p, u32 v){
|
||||
#if SQLITE_BYTEORDER==4321
|
||||
memcpy(p,&v,4);
|
||||
#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__)
|
||||
#elif SQLITE_BYTEORDER==1234 && defined(__GNUC__) && GCC_VERSION>=4003000
|
||||
u32 x = __builtin_bswap32(v);
|
||||
memcpy(p,&x,4);
|
||||
#elif SQLITE_BYTEORDER==1234 && defined(_MSC_VER) && _MSC_VER>=1300
|
||||
|
@ -53,6 +53,31 @@ static int vdbeSafetyNotNull(Vdbe *p){
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/*
|
||||
** Invoke the profile callback. This routine is only called if we already
|
||||
** know that the profile callback is defined and needs to be invoked.
|
||||
*/
|
||||
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
|
||||
sqlite3_int64 iNow;
|
||||
assert( p->startTime>0 );
|
||||
assert( db->xProfile!=0 );
|
||||
assert( db->init.busy==0 );
|
||||
assert( p->zSql!=0 );
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
|
||||
db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
|
||||
p->startTime = 0;
|
||||
}
|
||||
/*
|
||||
** The checkProfileCallback(DB,P) macro checks to see if a profile callback
|
||||
** is needed, and it invokes the callback if it is needed.
|
||||
*/
|
||||
# define checkProfileCallback(DB,P) \
|
||||
if( ((P)->startTime)>0 ){ invokeProfileCallback(DB,P); }
|
||||
#else
|
||||
# define checkProfileCallback(DB,P) /*no-op*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following routine destroys a virtual machine that is created by
|
||||
** the sqlite3_compile() routine. The integer returned is an SQLITE_
|
||||
@ -73,6 +98,7 @@ int sqlite3_finalize(sqlite3_stmt *pStmt){
|
||||
sqlite3 *db = v->db;
|
||||
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
checkProfileCallback(db, v);
|
||||
rc = sqlite3VdbeFinalize(v);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3LeaveMutexAndCloseZombie(db);
|
||||
@ -94,12 +120,14 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
Vdbe *v = (Vdbe*)pStmt;
|
||||
sqlite3_mutex_enter(v->db->mutex);
|
||||
sqlite3 *db = v->db;
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
checkProfileCallback(db, v);
|
||||
rc = sqlite3VdbeReset(v);
|
||||
sqlite3VdbeRewind(v);
|
||||
assert( (rc & (v->db->errMask))==rc );
|
||||
rc = sqlite3ApiExit(v->db, rc);
|
||||
sqlite3_mutex_leave(v->db->mutex);
|
||||
assert( (rc & (db->errMask))==rc );
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -450,6 +478,7 @@ static int doWalCallbacks(sqlite3 *db){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Execute the statement pStmt, either until a row of data is ready, the
|
||||
** statement is completely executed or an error occurs.
|
||||
@ -518,8 +547,10 @@ static int sqlite3Step(Vdbe *p){
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xProfile && !db->init.busy ){
|
||||
if( db->xProfile && !db->init.busy && p->zSql ){
|
||||
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
||||
}else{
|
||||
assert( p->startTime==0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -543,13 +574,8 @@ static int sqlite3Step(Vdbe *p){
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Invoke the profile callback if there is one
|
||||
*/
|
||||
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)*1000000);
|
||||
}
|
||||
/* If the statement completed successfully, invoke the profile callback */
|
||||
if( rc!=SQLITE_ROW ) checkProfileCallback(db, p);
|
||||
#endif
|
||||
|
||||
if( rc==SQLITE_DONE ){
|
||||
|
@ -3346,6 +3346,7 @@ static int vdbeRecordCompareDebug(
|
||||
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
|
||||
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
if( szHdr1>98307 ) return SQLITE_CORRUPT;
|
||||
d1 = szHdr1;
|
||||
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
|
@ -18,6 +18,8 @@ set ::testprefix fts3fault
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
if 0 {
|
||||
|
||||
# Test error handling in the sqlite3Fts3Init() function. This is the
|
||||
# function that registers the FTS3 module and various support functions
|
||||
# with SQLite.
|
||||
@ -157,6 +159,9 @@ do_faultsim_test 7.3 -prep {
|
||||
{1 {SQL logic error or missing database}}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
proc mit {blob} {
|
||||
set scan(littleEndian) i*
|
||||
set scan(bigEndian) I*
|
||||
@ -176,7 +181,7 @@ do_test 8.0 {
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
|
||||
do_faultsim_test 8.1 -prep {
|
||||
do_faultsim_test 8.1 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
} -body {
|
||||
@ -184,6 +189,7 @@ do_faultsim_test 8.1 -prep {
|
||||
} -test {
|
||||
faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
|
||||
}
|
||||
|
||||
do_faultsim_test 8.2 -faults oom-t* -prep {
|
||||
faultsim_restore_and_reopen
|
||||
db func mit mit
|
||||
|
124
test/fts3offsets.test
Normal file
124
test/fts3offsets.test
Normal file
@ -0,0 +1,124 @@
|
||||
# 2010 November 02
|
||||
#
|
||||
# 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
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
set testprefix fts3offsets
|
||||
set sqlite_fts3_enable_parentheses 1
|
||||
|
||||
proc extract {offsets text} {
|
||||
set res ""
|
||||
|
||||
set off [list]
|
||||
foreach {t i s n} $offsets {
|
||||
lappend off [list $s $n]
|
||||
}
|
||||
set off [lsort -integer -index 0 $off]
|
||||
|
||||
set iOff 0
|
||||
foreach e $off {
|
||||
foreach {s n} $e {}
|
||||
append res [string range $text $iOff $s-1]
|
||||
append res "("
|
||||
append res [string range $text $s [expr $s+$n-1]]
|
||||
append res ")"
|
||||
set iOff [expr $s+$n]
|
||||
}
|
||||
append res [string range $text $iOff end]
|
||||
|
||||
set res
|
||||
}
|
||||
db func extract extract
|
||||
|
||||
|
||||
do_execsql_test 1.1.0 {
|
||||
CREATE VIRTUAL TABLE xx USING fts3(x);
|
||||
INSERT INTO xx VALUES('A x x x B C x x');
|
||||
INSERT INTO xx VALUES('A B C x B x x C');
|
||||
INSERT INTO xx VALUES('A x x B C x x x');
|
||||
}
|
||||
do_execsql_test 1.1.1 {
|
||||
SELECT oid,extract(offsets(xx), x) FROM xx WHERE xx MATCH 'a OR (b NEAR/1 c)';
|
||||
} {
|
||||
1 {(A) x x x (B) (C) x x}
|
||||
2 {(A) (B) (C) x (B) x x C}
|
||||
3 {(A) x x (B) (C) x x x}
|
||||
}
|
||||
|
||||
do_execsql_test 1.2 {
|
||||
DELETE FROM xx;
|
||||
INSERT INTO xx VALUES('A x x x B C x x');
|
||||
INSERT INTO xx VALUES('A x x C x x x C');
|
||||
INSERT INTO xx VALUES('A x x B C x x x');
|
||||
}
|
||||
do_execsql_test 1.2.1 {
|
||||
SELECT oid,extract(offsets(xx), x) FROM xx WHERE xx MATCH 'a OR (b NEAR/1 c)';
|
||||
} {
|
||||
1 {(A) x x x (B) (C) x x}
|
||||
2 {(A) x x C x x x C}
|
||||
3 {(A) x x (B) (C) x x x}
|
||||
}
|
||||
|
||||
do_execsql_test 1.3 {
|
||||
DELETE FROM xx;
|
||||
INSERT INTO xx(rowid, x) VALUES(1, 'A B C');
|
||||
INSERT INTO xx(rowid, x) VALUES(2, 'A x');
|
||||
INSERT INTO xx(rowid, x) VALUES(3, 'A B C');
|
||||
INSERT INTO xx(rowid, x) VALUES(4, 'A B C x x x x x x x B');
|
||||
INSERT INTO xx(rowid, x) VALUES(5, 'A x x x x x x x x x C');
|
||||
INSERT INTO xx(rowid, x) VALUES(6, 'A x x x x x x x x x x x B');
|
||||
INSERT INTO xx(rowid, x) VALUES(7, 'A B C');
|
||||
}
|
||||
do_execsql_test 1.3.1 {
|
||||
SELECT oid,extract(offsets(xx), x) FROM xx WHERE xx MATCH 'a OR (b NEAR/1 c)';
|
||||
} {
|
||||
1 {(A) (B) (C)}
|
||||
2 {(A) x}
|
||||
3 {(A) (B) (C)}
|
||||
4 {(A) (B) (C) x x x x x x x B}
|
||||
5 {(A) x x x x x x x x x C}
|
||||
6 {(A) x x x x x x x x x x x B}
|
||||
7 {(A) (B) (C)}
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.4 {
|
||||
DELETE FROM xx;
|
||||
INSERT INTO xx(rowid, x) VALUES(7, 'A B C');
|
||||
INSERT INTO xx(rowid, x) VALUES(6, 'A x');
|
||||
INSERT INTO xx(rowid, x) VALUES(5, 'A B C');
|
||||
INSERT INTO xx(rowid, x) VALUES(4, 'A B C x x x x x x x B');
|
||||
INSERT INTO xx(rowid, x) VALUES(3, 'A x x x x x x x x x C');
|
||||
INSERT INTO xx(rowid, x) VALUES(2, 'A x x x x x x x x x x x B');
|
||||
INSERT INTO xx(rowid, x) VALUES(1, 'A B C');
|
||||
}
|
||||
do_execsql_test 1.4.1 {
|
||||
SELECT oid,extract(offsets(xx), x) FROM xx WHERE xx MATCH 'a OR (b NEAR/1 c)'
|
||||
ORDER BY docid DESC;
|
||||
} {
|
||||
7 {(A) (B) (C)}
|
||||
6 {(A) x}
|
||||
5 {(A) (B) (C)}
|
||||
4 {(A) (B) (C) x x x x x x x B}
|
||||
3 {(A) x x x x x x x x x C}
|
||||
2 {(A) x x x x x x x x x x x B}
|
||||
1 {(A) (B) (C)}
|
||||
}
|
||||
|
||||
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
finish_test
|
||||
|
@ -419,11 +419,10 @@ ifcapable autovacuum {
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
INSERT INTO t1 VALUES(randstr(1000,1000));
|
||||
}
|
||||
set memused [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
set pgovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 1]
|
||||
set before [db one {PRAGMA page_count}]
|
||||
execsql { DELETE FROM t1 }
|
||||
set memused2 [lindex [sqlite3_status SQLITE_STATUS_MEMORY_USED 0] 1]
|
||||
expr {($memused2 + 2048 < $memused) || $pgovfl==0}
|
||||
set after [db one {PRAGMA page_count}]
|
||||
expr {$before>$after}
|
||||
} {1}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ set xtra_size 290
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_lookaside 0 0
|
||||
sqlite3_config_pagecache 0 0
|
||||
sqlite3_initialize
|
||||
reset_highwater_marks
|
||||
build_test_db memsubsys1-1 {PRAGMA page_size=1024}
|
||||
@ -115,10 +116,10 @@ do_test memsubsys1-2.5 {
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_pagecache [expr 512+$xtra_size] 20
|
||||
sqlite3_config singlethread
|
||||
sqlite3_initialize
|
||||
reset_highwater_marks
|
||||
build_test_db memsubsys1-3.1 {PRAGMA page_size=1024}
|
||||
#show_memstats
|
||||
do_test memsubsys1-3.1.3 {
|
||||
set pg_used [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 2]
|
||||
} 0
|
||||
@ -312,6 +313,7 @@ sqlite3_config_memstatus 1
|
||||
sqlite3_config_pagecache 0 0
|
||||
sqlite3_config_scratch 0 0
|
||||
sqlite3_config_lookaside 100 500
|
||||
sqlite3_config serialized
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
finish_test
|
||||
|
@ -37,9 +37,9 @@ proc mutex_counters {varname} {
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests mutex1-1.* test that sqlite3_config() returns SQLITE_MISUSE if
|
||||
# is called at the wrong time. And that the first time sqlite3_initialize
|
||||
# is called at the wrong time. And that the first time sqlite3_initialize
|
||||
# is called it obtains the 'static_master' mutex 3 times and a recursive
|
||||
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops
|
||||
# mutex (sqlite3Config.pInitMutex) twice. Subsequent calls are no-ops
|
||||
# that do not require any mutexes.
|
||||
#
|
||||
do_test mutex1-1.0 {
|
||||
@ -102,12 +102,16 @@ ifcapable threadsafe&&shared_cache {
|
||||
foreach {mode mutexes} {
|
||||
singlethread {}
|
||||
multithread {
|
||||
fast static_lru static_master static_mem static_open static_prng
|
||||
static_pmem
|
||||
fast static_app1 static_app2 static_app3
|
||||
static_lru static_master static_mem static_open
|
||||
static_prng static_pmem static_vfs1 static_vfs2
|
||||
static_vfs3
|
||||
}
|
||||
serialized {
|
||||
fast recursive static_lru static_master static_mem static_open
|
||||
static_prng static_pmem
|
||||
fast recursive static_app1 static_app2
|
||||
static_app3 static_lru static_master static_mem
|
||||
static_open static_prng static_pmem static_vfs1
|
||||
static_vfs2 static_vfs3
|
||||
}
|
||||
} {
|
||||
|
||||
@ -129,9 +133,28 @@ ifcapable threadsafe&&shared_cache {
|
||||
ifcapable !memorymanage {
|
||||
regsub { static_lru} $mutexes {} mutexes
|
||||
}
|
||||
do_test mutex1.2.$mode.3 {
|
||||
if {$mode ne "singlethread"} {
|
||||
do_test mutex1.2.$mode.3 {
|
||||
#
|
||||
# NOTE: Make sure all the app and vfs mutexes get used.
|
||||
#
|
||||
enter_static_mutex static_app1
|
||||
leave_static_mutex static_app1
|
||||
enter_static_mutex static_app2
|
||||
leave_static_mutex static_app2
|
||||
enter_static_mutex static_app3
|
||||
leave_static_mutex static_app3
|
||||
enter_static_mutex static_vfs1
|
||||
leave_static_mutex static_vfs1
|
||||
enter_static_mutex static_vfs2
|
||||
leave_static_mutex static_vfs2
|
||||
enter_static_mutex static_vfs3
|
||||
leave_static_mutex static_vfs3
|
||||
} {}
|
||||
}
|
||||
do_test mutex1.2.$mode.4 {
|
||||
mutex_counters counters
|
||||
|
||||
|
||||
set res [list]
|
||||
foreach {key value} [array get counters] {
|
||||
if {$key ne "total" && $value > 0} {
|
||||
|
@ -24,6 +24,7 @@ do_test pcache2-1.1 {
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_pagecache 6000 100
|
||||
sqlite3_config singlethread
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
sqlite3_status SQLITE_STATUS_PAGECACHE_USED 1
|
||||
@ -73,6 +74,7 @@ catch {db2 close}
|
||||
sqlite3_reset_auto_extension
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_pagecache 0 0
|
||||
sqlite3_config serialized
|
||||
sqlite3_initialize
|
||||
autoinstall_test_functions
|
||||
|
||||
|
@ -15,6 +15,8 @@ static const char zHelp[] =
|
||||
" --journal M Set the journal_mode to M\n"
|
||||
" --key KEY Set the encryption key to KEY\n"
|
||||
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
|
||||
" --multithread Set multithreaded mode\n"
|
||||
" --nomemstat Disable memory statistics\n"
|
||||
" --nosync Set PRAGMA synchronous=OFF\n"
|
||||
" --notnull Add NOT NULL constraints to table columns\n"
|
||||
" --pagesize N Set the page size to N\n"
|
||||
@ -22,6 +24,8 @@ static const char zHelp[] =
|
||||
" --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
|
||||
" --reprepare Reprepare each statement upon every invocation\n"
|
||||
" --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n"
|
||||
" --serialized Set serialized threading mode\n"
|
||||
" --singlethread Set single-threaded mode - disables all mutexing\n"
|
||||
" --sqlonly No-op. Only show the SQL that would have been run.\n"
|
||||
" --shrink-memory Invoke sqlite3_db_release_memory() frequently.\n"
|
||||
" --size N Relative test size. Default=100\n"
|
||||
@ -1173,6 +1177,7 @@ int main(int argc, char **argv){
|
||||
int noSync = 0; /* True for --nosync */
|
||||
int pageSize = 0; /* Desired page size. 0 means default */
|
||||
int nPCache = 0, szPCache = 0;/* --pcache configuration */
|
||||
int doPCache = 0; /* True if --pcache is seen */
|
||||
int nScratch = 0, szScratch=0;/* --scratch configuration */
|
||||
int showStats = 0; /* True for --stats */
|
||||
int nThread = 0; /* --threads value */
|
||||
@ -1227,6 +1232,10 @@ int main(int argc, char **argv){
|
||||
nLook = integerValue(argv[i+1]);
|
||||
szLook = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"multithread")==0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||
}else if( strcmp(z,"nomemstat")==0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0);
|
||||
}else if( strcmp(z,"nosync")==0 ){
|
||||
noSync = 1;
|
||||
}else if( strcmp(z,"notnull")==0 ){
|
||||
@ -1243,6 +1252,7 @@ int main(int argc, char **argv){
|
||||
if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
|
||||
nPCache = integerValue(argv[i+1]);
|
||||
szPCache = integerValue(argv[i+2]);
|
||||
doPCache = 1;
|
||||
i += 2;
|
||||
}else if( strcmp(z,"primarykey")==0 ){
|
||||
g.zPK = "PRIMARY KEY";
|
||||
@ -1253,6 +1263,10 @@ int main(int argc, char **argv){
|
||||
nScratch = integerValue(argv[i+1]);
|
||||
szScratch = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"serialized")==0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_SERIALIZED);
|
||||
}else if( strcmp(z,"singlethread")==0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
}else if( strcmp(z,"sqlonly")==0 ){
|
||||
g.bSqlOnly = 1;
|
||||
}else if( strcmp(z,"shrink-memory")==0 ){
|
||||
@ -1305,10 +1319,12 @@ int main(int argc, char **argv){
|
||||
rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
|
||||
if( rc ) fatal_error("heap configuration failed: %d\n", rc);
|
||||
}
|
||||
if( nPCache>0 && szPCache>0 ){
|
||||
pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
|
||||
if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
|
||||
nPCache*(sqlite3_int64)szPCache);
|
||||
if( doPCache ){
|
||||
if( nPCache>0 && szPCache>0 ){
|
||||
pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
|
||||
if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
|
||||
nPCache*(sqlite3_int64)szPCache);
|
||||
}
|
||||
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
|
||||
if( rc ) fatal_error("pcache configuration failed: %d\n", rc);
|
||||
}
|
||||
|
@ -169,6 +169,14 @@ do_test trace-4.5 {
|
||||
} {{SELECT * FROM t1}}
|
||||
catch {sqlite3_finalize $STMT}
|
||||
|
||||
# 3.8.11: Profile output even if the statement is not run to completion.
|
||||
do_test trace-4.6 {
|
||||
set TRACE_OUT {}
|
||||
db eval {SELECT * FROM t1} {} {if {$a>=1} break}
|
||||
set TRACE_OUT
|
||||
} {{SELECT * FROM t1}}
|
||||
|
||||
|
||||
# Trigger tracing.
|
||||
#
|
||||
ifcapable trigger {
|
||||
|
@ -857,5 +857,12 @@ do_catchsql_test 15.1 {
|
||||
SELECT x FROM d;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# 2015-07-05: Do not allow aggregate recursive queries
|
||||
#
|
||||
do_catchsql_test 16.1 {
|
||||
WITH RECURSIVE
|
||||
i(x) AS (VALUES(1) UNION SELECT count(*) FROM i)
|
||||
SELECT * FROM i;
|
||||
} {1 {recursive aggregate queries not supported}}
|
||||
|
||||
finish_test
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** 2013-06-10
|
||||
** 2014-07-28
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
@ -9,6 +9,10 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements a utility program that will load many disk
|
||||
** files (all files under a given directory) into a FTS table. This is
|
||||
** used for performance testing of FTS3, FTS4, and FTS5.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
Loading…
Reference in New Issue
Block a user