Merge latest trunk changes with this branch.
FossilOrigin-Name: 76212f2c9a3c3ff0e238d6dad776938c6af674e6
This commit is contained in:
commit
32348f7bd2
30
Makefile.msc
30
Makefile.msc
@ -714,7 +714,7 @@ LIBRESOBJS =
|
||||
|
||||
# All of the source code files.
|
||||
#
|
||||
SRC = \
|
||||
SRC1 = \
|
||||
$(TOP)\src\alter.c \
|
||||
$(TOP)\src\analyze.c \
|
||||
$(TOP)\src\attach.c \
|
||||
@ -764,7 +764,8 @@ SRC = \
|
||||
$(TOP)\src\os_setup.h \
|
||||
$(TOP)\src\os_unix.c \
|
||||
$(TOP)\src\os_win.c \
|
||||
$(TOP)\src\os_win.h \
|
||||
$(TOP)\src\os_win.h
|
||||
SRC2 = \
|
||||
$(TOP)\src\pager.c \
|
||||
$(TOP)\src\pager.h \
|
||||
$(TOP)\src\parse.y \
|
||||
@ -811,15 +812,14 @@ SRC = \
|
||||
|
||||
# Source code for extensions
|
||||
#
|
||||
SRC = $(SRC) \
|
||||
SRC3 = \
|
||||
$(TOP)\ext\fts1\fts1.c \
|
||||
$(TOP)\ext\fts1\fts1.h \
|
||||
$(TOP)\ext\fts1\fts1_hash.c \
|
||||
$(TOP)\ext\fts1\fts1_hash.h \
|
||||
$(TOP)\ext\fts1\fts1_porter.c \
|
||||
$(TOP)\ext\fts1\fts1_tokenizer.h \
|
||||
$(TOP)\ext\fts1\fts1_tokenizer1.c
|
||||
SRC = $(SRC) \
|
||||
$(TOP)\ext\fts1\fts1_tokenizer1.c \
|
||||
$(TOP)\ext\fts2\fts2.c \
|
||||
$(TOP)\ext\fts2\fts2.h \
|
||||
$(TOP)\ext\fts2\fts2_hash.c \
|
||||
@ -829,7 +829,7 @@ SRC = $(SRC) \
|
||||
$(TOP)\ext\fts2\fts2_tokenizer.h \
|
||||
$(TOP)\ext\fts2\fts2_tokenizer.c \
|
||||
$(TOP)\ext\fts2\fts2_tokenizer1.c
|
||||
SRC = $(SRC) \
|
||||
SRC4 = \
|
||||
$(TOP)\ext\fts3\fts3.c \
|
||||
$(TOP)\ext\fts3\fts3.h \
|
||||
$(TOP)\ext\fts3\fts3Int.h \
|
||||
@ -846,18 +846,16 @@ SRC = $(SRC) \
|
||||
$(TOP)\ext\fts3\fts3_tokenize_vtab.c \
|
||||
$(TOP)\ext\fts3\fts3_unicode.c \
|
||||
$(TOP)\ext\fts3\fts3_unicode2.c \
|
||||
$(TOP)\ext\fts3\fts3_write.c
|
||||
SRC = $(SRC) \
|
||||
$(TOP)\ext\fts3\fts3_write.c \
|
||||
$(TOP)\ext\icu\sqliteicu.h \
|
||||
$(TOP)\ext\icu\icu.c
|
||||
SRC = $(SRC) \
|
||||
$(TOP)\ext\icu\icu.c \
|
||||
$(TOP)\ext\rtree\rtree.h \
|
||||
$(TOP)\ext\rtree\rtree.c
|
||||
|
||||
|
||||
# Generated source code files
|
||||
#
|
||||
SRC = $(SRC) \
|
||||
SRC5 = \
|
||||
keywordhash.h \
|
||||
opcodes.c \
|
||||
opcodes.h \
|
||||
@ -865,6 +863,10 @@ SRC = $(SRC) \
|
||||
parse.h \
|
||||
sqlite3.h
|
||||
|
||||
# All source code files.
|
||||
#
|
||||
SRC = $(SRC1) $(SRC2) $(SRC3) $(SRC4) $(SRC5)
|
||||
|
||||
# Source code to the test files.
|
||||
#
|
||||
TESTSRC = \
|
||||
@ -1052,7 +1054,11 @@ mptester.exe: $(TOP)\mptest\mptest.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h
|
||||
.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl
|
||||
-rmdir /S/Q tsrc
|
||||
-mkdir tsrc
|
||||
for %i in ($(SRC)) do copy /Y %i tsrc
|
||||
for %i in ($(SRC1)) do copy /Y %i tsrc
|
||||
for %i in ($(SRC2)) do copy /Y %i tsrc
|
||||
for %i in ($(SRC3)) do copy /Y %i tsrc
|
||||
for %i in ($(SRC4)) do copy /Y %i tsrc
|
||||
for %i in ($(SRC5)) do copy /Y %i tsrc
|
||||
del /Q tsrc\sqlite.h.in tsrc\parse.y
|
||||
$(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
|
||||
move vdbe.new tsrc\vdbe.c
|
||||
|
132
ext/fts3/fts3.c
132
ext/fts3/fts3.c
@ -3164,10 +3164,17 @@ static int fts3FilterMethod(
|
||||
** row by docid.
|
||||
*/
|
||||
if( eSearch==FTS3_FULLSCAN_SEARCH ){
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT %s ORDER BY rowid %s",
|
||||
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
|
||||
);
|
||||
if( pDocidGe || pDocidLe ){
|
||||
zSql = sqlite3_mprintf(
|
||||
"SELECT %s WHERE rowid BETWEEN %lld AND %lld ORDER BY rowid %s",
|
||||
p->zReadExprlist, pCsr->iMinDocid, pCsr->iMaxDocid,
|
||||
(pCsr->bDesc ? "DESC" : "ASC")
|
||||
);
|
||||
}else{
|
||||
zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
|
||||
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
|
||||
);
|
||||
}
|
||||
if( zSql ){
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
@ -5020,6 +5027,22 @@ static void fts3EvalNextRow(
|
||||
}
|
||||
pExpr->iDocid = pLeft->iDocid;
|
||||
pExpr->bEof = (pLeft->bEof || pRight->bEof);
|
||||
if( pExpr->eType==FTSQUERY_NEAR && pExpr->bEof ){
|
||||
if( pRight->pPhrase && pRight->pPhrase->doclist.aAll ){
|
||||
Fts3Doclist *pDl = &pRight->pPhrase->doclist;
|
||||
while( *pRc==SQLITE_OK && pRight->bEof==0 ){
|
||||
memset(pDl->pList, 0, pDl->nList);
|
||||
fts3EvalNextRow(pCsr, pRight, pRc);
|
||||
}
|
||||
}
|
||||
if( pLeft->pPhrase && pLeft->pPhrase->doclist.aAll ){
|
||||
Fts3Doclist *pDl = &pLeft->pPhrase->doclist;
|
||||
while( *pRc==SQLITE_OK && pLeft->bEof==0 ){
|
||||
memset(pDl->pList, 0, pDl->nList);
|
||||
fts3EvalNextRow(pCsr, pLeft, pRc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5392,6 +5415,7 @@ static void fts3EvalRestart(
|
||||
}
|
||||
pPhrase->doclist.pNextDocid = 0;
|
||||
pPhrase->doclist.iDocid = 0;
|
||||
pPhrase->pOrPoslist = 0;
|
||||
}
|
||||
|
||||
pExpr->iDocid = 0;
|
||||
@ -5637,8 +5661,8 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
iDocid = pExpr->iDocid;
|
||||
pIter = pPhrase->doclist.pList;
|
||||
if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
|
||||
int rc = SQLITE_OK;
|
||||
int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */
|
||||
int iMul; /* +1 if csr dir matches index dir, else -1 */
|
||||
int bOr = 0;
|
||||
u8 bEof = 0;
|
||||
u8 bTreeEof = 0;
|
||||
@ -5662,72 +5686,43 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
** an incremental phrase. Load the entire doclist for the phrase
|
||||
** into memory in this case. */
|
||||
if( pPhrase->bIncr ){
|
||||
int rc = SQLITE_OK;
|
||||
int bEofSave = pExpr->bEof;
|
||||
fts3EvalRestart(pCsr, pExpr, &rc);
|
||||
while( rc==SQLITE_OK && !pExpr->bEof ){
|
||||
fts3EvalNextRow(pCsr, pExpr, &rc);
|
||||
if( bEofSave==0 && pExpr->iDocid==iDocid ) break;
|
||||
int bEofSave = pNear->bEof;
|
||||
fts3EvalRestart(pCsr, pNear, &rc);
|
||||
while( rc==SQLITE_OK && !pNear->bEof ){
|
||||
fts3EvalNextRow(pCsr, pNear, &rc);
|
||||
if( bEofSave==0 && pNear->iDocid==iDocid ) break;
|
||||
}
|
||||
pIter = pPhrase->doclist.pList;
|
||||
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
iMul = ((pCsr->bDesc==bDescDoclist) ? 1 : -1);
|
||||
while( bTreeEof==1
|
||||
&& pNear->bEof==0
|
||||
&& (DOCID_CMP(pNear->iDocid, pCsr->iPrevId) * iMul)<0
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
fts3EvalNextRow(pCsr, pExpr, &rc);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
iDocid = pExpr->iDocid;
|
||||
pIter = pPhrase->doclist.pList;
|
||||
}
|
||||
|
||||
bEof = (pPhrase->doclist.nAll==0);
|
||||
assert( bDescDoclist==0 || bDescDoclist==1 );
|
||||
assert( pCsr->bDesc==0 || pCsr->bDesc==1 );
|
||||
|
||||
if( bEof==0 ){
|
||||
if( pCsr->bDesc==bDescDoclist ){
|
||||
int dummy;
|
||||
if( pNear->bEof ){
|
||||
/* This expression is already at EOF. So position it to point to the
|
||||
** last entry in the doclist at pPhrase->doclist.aAll[]. Variable
|
||||
** iDocid is already set for this entry, so all that is required is
|
||||
** to set pIter to point to the first byte of the last position-list
|
||||
** in the doclist.
|
||||
**
|
||||
** It would also be correct to set pIter and iDocid to zero. In
|
||||
** this case, the first call to sqltie3Fts4DoclistPrev() below
|
||||
** would also move the iterator to point to the last entry in the
|
||||
** doclist. However, this is expensive, as to do so it has to
|
||||
** iterate through the entire doclist from start to finish (since
|
||||
** it does not know the docid for the last entry). */
|
||||
pIter = &pPhrase->doclist.aAll[pPhrase->doclist.nAll-1];
|
||||
fts3ReversePoslist(pPhrase->doclist.aAll, &pIter);
|
||||
}
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
|
||||
sqlite3Fts3DoclistPrev(
|
||||
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
|
||||
&pIter, &iDocid, &dummy, &bEof
|
||||
);
|
||||
}
|
||||
}else{
|
||||
if( pNear->bEof ){
|
||||
pIter = 0;
|
||||
iDocid = 0;
|
||||
}
|
||||
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
|
||||
sqlite3Fts3DoclistNext(
|
||||
bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll,
|
||||
&pIter, &iDocid, &bEof
|
||||
);
|
||||
}
|
||||
if( bTreeEof ){
|
||||
while( rc==SQLITE_OK && !pNear->bEof ){
|
||||
fts3EvalNextRow(pCsr, pNear, &rc);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
pIter = pPhrase->pOrPoslist;
|
||||
iDocid = pPhrase->iOrDocid;
|
||||
if( pCsr->bDesc==bDescDoclist ){
|
||||
bEof = (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;
|
||||
|
||||
if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
|
||||
}
|
||||
@ -5741,10 +5736,13 @@ int sqlite3Fts3EvalPhrasePoslist(
|
||||
}
|
||||
while( iThis<iCol ){
|
||||
fts3ColumnlistCopy(0, &pIter);
|
||||
if( *pIter==0x00 ) return 0;
|
||||
if( *pIter==0x00 ) return SQLITE_OK;
|
||||
pIter++;
|
||||
pIter += fts3GetVarint32(pIter, &iThis);
|
||||
}
|
||||
if( *pIter==0x00 ){
|
||||
pIter = 0;
|
||||
}
|
||||
|
||||
*ppOut = ((iCol==iThis)?pIter:0);
|
||||
return SQLITE_OK;
|
||||
|
@ -375,6 +375,11 @@ struct Fts3Phrase {
|
||||
int bIncr; /* True if doclist is loaded incrementally */
|
||||
int iDoclistToken;
|
||||
|
||||
/* Used by sqlite3Fts3EvalPhrasePoslist() if this is a descendent of an
|
||||
** OR condition. */
|
||||
char *pOrPoslist;
|
||||
i64 iOrDocid;
|
||||
|
||||
/* Variables below this point are populated by fts3_expr.c when parsing
|
||||
** a MATCH expression. Everything above is part of the evaluation phase.
|
||||
*/
|
||||
|
@ -442,37 +442,39 @@ static int fts3BestSnippet(
|
||||
sIter.nSnippet = nSnippet;
|
||||
sIter.nPhrase = nList;
|
||||
sIter.iCurrent = -1;
|
||||
(void)fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
|
||||
rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void *)&sIter);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
/* Set the *pmSeen output variable. */
|
||||
for(i=0; i<nList; i++){
|
||||
if( sIter.aPhrase[i].pHead ){
|
||||
*pmSeen |= (u64)1 << i;
|
||||
/* Set the *pmSeen output variable. */
|
||||
for(i=0; i<nList; i++){
|
||||
if( sIter.aPhrase[i].pHead ){
|
||||
*pmSeen |= (u64)1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop through all candidate snippets. Store the best snippet in
|
||||
** *pFragment. Store its associated 'score' in iBestScore.
|
||||
*/
|
||||
pFragment->iCol = iCol;
|
||||
while( !fts3SnippetNextCandidate(&sIter) ){
|
||||
int iPos;
|
||||
int iScore;
|
||||
u64 mCover;
|
||||
u64 mHighlight;
|
||||
fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover, &mHighlight);
|
||||
assert( iScore>=0 );
|
||||
if( iScore>iBestScore ){
|
||||
pFragment->iPos = iPos;
|
||||
pFragment->hlmask = mHighlight;
|
||||
pFragment->covered = mCover;
|
||||
iBestScore = iScore;
|
||||
/* Loop through all candidate snippets. Store the best snippet in
|
||||
** *pFragment. Store its associated 'score' in iBestScore.
|
||||
*/
|
||||
pFragment->iCol = iCol;
|
||||
while( !fts3SnippetNextCandidate(&sIter) ){
|
||||
int iPos;
|
||||
int iScore;
|
||||
u64 mCover;
|
||||
u64 mHighlite;
|
||||
fts3SnippetDetails(&sIter, mCovered, &iPos, &iScore, &mCover,&mHighlite);
|
||||
assert( iScore>=0 );
|
||||
if( iScore>iBestScore ){
|
||||
pFragment->iPos = iPos;
|
||||
pFragment->hlmask = mHighlite;
|
||||
pFragment->covered = mCover;
|
||||
iBestScore = iScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*piScore = iBestScore;
|
||||
}
|
||||
sqlite3_free(sIter.aPhrase);
|
||||
*piScore = iBestScore;
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -680,8 +682,12 @@ static int fts3SnippetText(
|
||||
** required. They are required if (a) this is not the first fragment,
|
||||
** or (b) this fragment does not begin at position 0 of its column.
|
||||
*/
|
||||
if( rc==SQLITE_OK && (iPos>0 || iFragment>0) ){
|
||||
rc = fts3StringAppend(pOut, zEllipsis, -1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iPos>0 || iFragment>0 ){
|
||||
rc = fts3StringAppend(pOut, zEllipsis, -1);
|
||||
}else if( iBegin ){
|
||||
rc = fts3StringAppend(pOut, zDoc, iBegin);
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK || iCurrent<iPos ) continue;
|
||||
}
|
||||
|
51
manifest
51
manifest
@ -1,9 +1,9 @@
|
||||
C Minor\soptimizations\sto\sfts5\swrites.
|
||||
D 2015-01-31T15:23:44.132
|
||||
C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
|
||||
D 2015-02-02T09:40:36.284
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 2b1cb8881bdefcb0a8ed41c34c81cfa630374222
|
||||
F Makefile.msc 1edfd7dd45d98a04f9a2fa81a01c49faeb628578
|
||||
F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858
|
||||
F README.md d58e3bebc0a4145e0f2a87994015fdb575a8e866
|
||||
F VERSION d846487aff892625eb8e75960234e7285f0462fe
|
||||
@ -78,16 +78,16 @@ 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 5c464816508e40feb3c61f1f5566551764698fc8
|
||||
F ext/fts3/fts3.c 56a78f7e65e9e59bd0e75a1e10ce406f62034ca8
|
||||
F ext/fts3/fts3.h 62a77d880cf06a2865052726f8325c8fabcecad7
|
||||
F ext/fts3/fts3Int.h 53d4eca1fb23eab00681fb028fb82eb5705c1e21
|
||||
F ext/fts3/fts3Int.h 394858c12a17740f7a1f6bd372c4606d4425a8d1
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
F ext/fts3/fts3_expr.c 40123785eaa3ebd4c45c9b23407cc44ac0c49905
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
|
||||
F ext/fts3/fts3_snippet.c 51beb5c1498176fd9caccaf1c75b55cb803a985a
|
||||
F ext/fts3/fts3_snippet.c f16ef6425f92339a8fecc87d9aaf2b12355c78e4
|
||||
F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763
|
||||
F ext/fts3/fts3_test.c 8a3a78c4458b2d7c631fcf4b152a5cd656fa7038
|
||||
F ext/fts3/fts3_tokenize_vtab.c becc661223db7898b213f9e8a23d75bac02408c9
|
||||
@ -218,16 +218,16 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
|
||||
F src/btree.c 4c098bb6e8678e4596983862abf78f7a0fcb807e
|
||||
F src/btree.c 2a1245df0356a229bcd0fd87a8536b5067f16e82
|
||||
F src/btree.h 94277c1d30c0b75705974bcc8b0c05e79c03d474
|
||||
F src/btreeInt.h a3d0ae1d511365e1a2b76ad10960dbe55c286f34
|
||||
F src/build.c f5cfd7b32216f695b995bbc7c1a395f6d451d11f
|
||||
F src/build.c eefaa4f1d86bc3c08023a61fdd1e695b47796975
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/complete.c 198a0066ba60ab06fc00fba1998d870a4d575463
|
||||
F src/ctime.c 98f89724adc891a1a4c655bee04e33e716e05887
|
||||
F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac
|
||||
F src/delete.c bd1a91ddd247ce13004075251e0b7fe2bf9925ef
|
||||
F src/expr.c 33a4518b2c786903cb185dbdc66e071ac38d467e
|
||||
F src/expr.c abe930897ccafae3819fd2855cbc1b00c262fd12
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c e0444b61bed271a76840cbe6182df93a9baa3f12
|
||||
F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430
|
||||
@ -240,7 +240,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c 86bd4e2fccd520b748cba52492ab60c4a770f660
|
||||
F src/main.c aacb8f370a15d96f62cd1493556b0ba71f13859d
|
||||
F src/main.c fe876f31d6744341d9e2de4da66f33563edec9cb
|
||||
F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c abe6ee469b6c5a35c7f22bfeb9c9bac664a1c987
|
||||
@ -270,21 +270,21 @@ F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
|
||||
F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf
|
||||
F src/pragma.c ba149bbbc90783f84815636c509ced8eac11bbcf
|
||||
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
|
||||
F src/printf.c ea82bcb1b83273b4c67177c233c1f78c81fc42f9
|
||||
F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c a4e8fda24c8eab2682a058bdda0d5d68cfe3919c
|
||||
F src/shell.c d2d3b46701e44369dd314bd6817541c60e2c39ea
|
||||
F src/sqlite.h.in 9dfc99d6533d36d6a549c4f3f01cacc8be956ada
|
||||
F src/select.c 1f2087523007c42900ffcbdeaef06a23ad9329fc
|
||||
F src/shell.c 22b4406b0b59efd14b3b351a5809dda517df6d30
|
||||
F src/sqlite.h.in 54678c21401909f72b221344dd560d285a1ba5eb
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h eaf210295b551d4e40e622aec1b2261c0b28f844
|
||||
F src/sqliteInt.h c4e05f7489cd300f856e2283d5e61302ce826471
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 81712116e826b0089bb221b018929536b2b5406f
|
||||
F src/table.c e7a09215315a978057fb42c640f890160dbcc45e
|
||||
F src/tclsqlite.c d2a15339103ff7c61ab7766ea8f4f549997e6590
|
||||
F src/test1.c 00a74fbc6604e1bcd240726a9ff8d0cc123374e7
|
||||
F src/test1.c 90fbedce75330d48d99eadb7d5f4223e86969585
|
||||
F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d
|
||||
F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622
|
||||
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
|
||||
@ -347,7 +347,7 @@ F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
|
||||
F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2
|
||||
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
|
||||
F src/vtab.c ec672a0b5d507f24b9294c0696dbd2fd2ce9b122
|
||||
F src/wal.c 85353539f2d9d0c91ebd057c32525b1e1aa3335e
|
||||
F src/wal.c 39303f2c9db02a4e422cd8eb2c8760420c6a51fe
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c d46de821bc604a4fd36fa3928c086950e91aafb1
|
||||
@ -635,10 +635,10 @@ F test/fts3matchinfo.test 58544fa4d254000fa4e7f494b0a832f7ba61d45e
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1
|
||||
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
|
||||
F test/fts3query.test 4fefd43ff24993bc2c9b2778f2bec0cc7629e7ed
|
||||
F test/fts3query.test d81ffb0ab1d4e1a2a330b8eb1e160b60603f4745
|
||||
F test/fts3rnd.test 1320d8826a845e38a96e769562bf83d7a92a15d0
|
||||
F test/fts3shared.test 57e26a801f21027b7530da77db54286a6fe4997e
|
||||
F test/fts3snippet.test d524af6bcef4714e059ef559113dbdc924cd33d1
|
||||
F test/fts3snippet.test 03c2f3be7d3b7c8bb105ed237f204833392bd57f
|
||||
F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
|
||||
F test/fts3tok1.test c551043de056b0b1582a54e878991f57bad074bc
|
||||
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
|
||||
@ -665,7 +665,7 @@ F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test b34fe575aa10292135421ff4bf315de4cde7824a
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
@ -675,6 +675,7 @@ F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/hexlit.test f9ecde8145bfc2341573473256c74ae37a200497
|
||||
F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
@ -779,7 +780,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
|
||||
F test/misc1.test 1201a037c24f982cc0e956cdaa34fcaf6439c417
|
||||
F test/misc1.test 4864f2834b203cad7f688df8a5f725e4bab08029
|
||||
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
|
||||
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
|
||||
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
@ -1171,7 +1172,7 @@ F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
|
||||
F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 11b8658dd4d5448f4604124bebd9b68be5bc3e66
|
||||
F test/wal5.test 88b5d9a6a3d1532497ee9f4296f010d66f07e33c
|
||||
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
@ -1283,7 +1284,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 0e225b15357765f132c3364b222f9931a608a5b2
|
||||
R bf6974c43532ef38693ab05d4629d2ec
|
||||
P 1fffe51fa92f1784365140d5b163ab6c690981ae 42d5601739c90434e5adfda8fa99ef7b903877db
|
||||
R 668d2feec869c09e5368ca6aaf5507f3
|
||||
U dan
|
||||
Z 8f2a2071b0090e43c31fbea210c6dce0
|
||||
Z dfa214b77fdf4b594624abdda6f53f9b
|
||||
|
@ -1 +1 @@
|
||||
1fffe51fa92f1784365140d5b163ab6c690981ae
|
||||
76212f2c9a3c3ff0e238d6dad776938c6af674e6
|
@ -175,6 +175,12 @@ static int hasSharedCacheTableLock(
|
||||
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
|
||||
Index *pIdx = (Index *)sqliteHashData(p);
|
||||
if( pIdx->tnum==(int)iRoot ){
|
||||
if( iTab ){
|
||||
/* Two or more indexes share the same root page. There must
|
||||
** be imposter tables. So just return true. The assert is not
|
||||
** useful in that case. */
|
||||
return 1;
|
||||
}
|
||||
iTab = pIdx->pTable->tnum;
|
||||
}
|
||||
}
|
||||
|
11
src/build.c
11
src/build.c
@ -1731,11 +1731,14 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
||||
assert( pPk!=0 );
|
||||
nPk = pPk->nKeyCol;
|
||||
|
||||
/* Make sure every column of the PRIMARY KEY is NOT NULL */
|
||||
for(i=0; i<nPk; i++){
|
||||
pTab->aCol[pPk->aiColumn[i]].notNull = 1;
|
||||
/* Make sure every column of the PRIMARY KEY is NOT NULL. (Except,
|
||||
** do not enforce this for imposter tables.) */
|
||||
if( !db->init.imposterTable ){
|
||||
for(i=0; i<nPk; i++){
|
||||
pTab->aCol[pPk->aiColumn[i]].notNull = 1;
|
||||
}
|
||||
pPk->uniqNotNull = 1;
|
||||
}
|
||||
pPk->uniqNotNull = 1;
|
||||
|
||||
/* The root page of the PRIMARY KEY is the table root page */
|
||||
pPk->tnum = pTab->tnum;
|
||||
|
@ -132,9 +132,9 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
break;
|
||||
}
|
||||
if( p->pTab!=0
|
||||
&& (op==TK_AGG_COLUMN || op==TK_COLUMN
|
||||
if( (op==TK_AGG_COLUMN || op==TK_COLUMN
|
||||
|| op==TK_REGISTER || op==TK_TRIGGER)
|
||||
&& p->pTab!=0
|
||||
){
|
||||
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
|
28
src/main.c
28
src/main.c
@ -1969,6 +1969,7 @@ int sqlite3_wal_checkpoint_v2(
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "unknown database: %s", zDb);
|
||||
}else{
|
||||
db->busyHandler.nBusy = 0;
|
||||
rc = sqlite3Checkpoint(db, iDb, eMode, pnLog, pnCkpt);
|
||||
sqlite3Error(db, rc);
|
||||
}
|
||||
@ -3606,6 +3607,33 @@ int sqlite3_test_control(int op, ...){
|
||||
if( sqlite3GlobalConfig.isInit==0 ) rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, dbName, onOff, tnum);
|
||||
**
|
||||
** This test control is used to create imposter tables. "db" is a pointer
|
||||
** to the database connection. dbName is the database name (ex: "main" or
|
||||
** "temp") which will receive the imposter. "onOff" turns imposter mode on
|
||||
** or off. "tnum" is the root page of the b-tree to which the imposter
|
||||
** table should connect.
|
||||
**
|
||||
** Enable imposter mode only when the schema has already been parsed. Then
|
||||
** run a single CREATE TABLE statement to construct the imposter table in the
|
||||
** parsed schema. Then turn imposter mode back off again.
|
||||
**
|
||||
** If onOff==0 and tnum>0 then reset the schema for all databases, causing
|
||||
** the schema to be reparsed the next time it is needed. This has the
|
||||
** effect of erasing all imposter tables.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_IMPOSTER: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
|
||||
db->init.busy = db->init.imposterTable = va_arg(ap,int);
|
||||
db->init.newTnum = va_arg(ap,int);
|
||||
if( db->init.busy==0 && db->init.newTnum>0 ){
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
@ -212,13 +212,6 @@ void sqlite3VXPrintf(
|
||||
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
if( ap==0 ){
|
||||
(void)SQLITE_MISUSE_BKPT;
|
||||
sqlite3StrAccumReset(pAccum);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bufpt = 0;
|
||||
if( bFlags ){
|
||||
if( (bArgList = (bFlags & SQLITE_PRINTF_SQLFUNC))!=0 ){
|
||||
|
@ -4153,7 +4153,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
/* A sub-query in the FROM clause of a SELECT */
|
||||
assert( pSel!=0 );
|
||||
assert( pFrom->pTab==0 );
|
||||
sqlite3WalkSelect(pWalker, pSel);
|
||||
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
||||
pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
||||
if( pTab==0 ) return WRC_Abort;
|
||||
pTab->nRef = 1;
|
||||
|
20
src/shell.c
20
src/shell.c
@ -113,11 +113,11 @@ extern int pclose(FILE*);
|
||||
** routines take care of that.
|
||||
*/
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
static setBinaryMode(FILE *out){
|
||||
static void setBinaryMode(FILE *out){
|
||||
fflush(out);
|
||||
_setmode(_fileno(out), _O_BINARY);
|
||||
}
|
||||
static setTextMode(FILE *out){
|
||||
static void setTextMode(FILE *out){
|
||||
fflush(out);
|
||||
_setmode(_fileno(out), _O_TEXT);
|
||||
}
|
||||
@ -3329,7 +3329,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE)
|
||||
if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){
|
||||
extern int sqlite3SelectTrace;
|
||||
sqlite3SelectTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff;
|
||||
sqlite3SelectTrace = integerValue(azArg[1]);
|
||||
}else
|
||||
#endif
|
||||
|
||||
@ -3536,6 +3536,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
{ "byteorder", SQLITE_TESTCTRL_BYTEORDER },
|
||||
{ "never_corrupt", SQLITE_TESTCTRL_NEVER_CORRUPT },
|
||||
{ "imposter", SQLITE_TESTCTRL_IMPOSTER },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc = 0;
|
||||
@ -3628,6 +3629,18 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SQLITE_TESTCTRL_IMPOSTER:
|
||||
if( nArg==5 ){
|
||||
rc = sqlite3_test_control(testctrl, p->db,
|
||||
azArg[2],
|
||||
integerValue(azArg[3]),
|
||||
integerValue(azArg[4]));
|
||||
}else{
|
||||
fprintf(stderr,"Usage: .testctrl initmode dbName onoff tnum\n");
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SQLITE_TESTCTRL_BITVEC_TEST:
|
||||
case SQLITE_TESTCTRL_FAULT_INSTALL:
|
||||
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
|
||||
@ -4195,6 +4208,7 @@ int main(int argc, char **argv){
|
||||
}
|
||||
#endif
|
||||
setBinaryMode(stdin);
|
||||
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
|
||||
Argv0 = argv[0];
|
||||
main_init(&data);
|
||||
stdin_is_interactive = isatty(0);
|
||||
|
@ -6260,7 +6260,8 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
#define SQLITE_TESTCTRL_ISINIT 23
|
||||
#define SQLITE_TESTCTRL_SORTER_MMAP 24
|
||||
#define SQLITE_TESTCTRL_LAST 24
|
||||
#define SQLITE_TESTCTRL_IMPOSTER 25
|
||||
#define SQLITE_TESTCTRL_LAST 25
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
@ -1087,6 +1087,7 @@ struct sqlite3 {
|
||||
u8 iDb; /* Which db file is being initialized */
|
||||
u8 busy; /* TRUE if currently initializing */
|
||||
u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */
|
||||
u8 imposterTable; /* Building an imposter table */
|
||||
} init;
|
||||
int nVdbeActive; /* Number of VDBEs currently running */
|
||||
int nVdbeRead; /* Number of active VDBEs that read or write */
|
||||
|
19
src/test1.c
19
src/test1.c
@ -5914,7 +5914,8 @@ static int test_test_control(
|
||||
int i;
|
||||
} aVerb[] = {
|
||||
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
|
||||
{ "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
|
||||
{ "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
|
||||
{ "SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER },
|
||||
};
|
||||
int iVerb;
|
||||
int iFlag;
|
||||
@ -5955,6 +5956,22 @@ static int test_test_control(
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
|
||||
break;
|
||||
}
|
||||
|
||||
case SQLITE_TESTCTRL_IMPOSTER: {
|
||||
int onOff, tnum;
|
||||
const char *zDbName;
|
||||
sqlite3 *db;
|
||||
if( objc!=6 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
|
||||
zDbName = Tcl_GetString(objv[3]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR;
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
|
183
src/wal.c
183
src/wal.c
@ -1694,7 +1694,7 @@ static int walCheckpoint(
|
||||
int sync_flags, /* Flags for OsSync() (or 0) */
|
||||
u8 *zBuf /* Temporary buffer to use */
|
||||
){
|
||||
int rc; /* Return code */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int szPage; /* Database page-size */
|
||||
WalIterator *pIter = 0; /* Wal iterator context */
|
||||
u32 iDbpage = 0; /* Next database page to write */
|
||||
@ -1708,104 +1708,107 @@ static int walCheckpoint(
|
||||
testcase( szPage<=32768 );
|
||||
testcase( szPage>=65536 );
|
||||
pInfo = walCkptInfo(pWal);
|
||||
if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
|
||||
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
|
||||
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
** safe to write into the database. Frames beyond mxSafeFrame might
|
||||
** overwrite database pages that are in use by active readers and thus
|
||||
** cannot be backfilled from the WAL.
|
||||
*/
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y;
|
||||
xBusy = 0;
|
||||
}else{
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
/* Allocate the iterator */
|
||||
rc = walIteratorInit(pWal, &pIter);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
if( pInfo->nBackfill<mxSafeFrame
|
||||
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
|
||||
){
|
||||
i64 nSize; /* Current size of database file */
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
/* Sync the WAL to disk */
|
||||
if( sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* If the database may grow as a result of this checkpoint, hint
|
||||
** about the eventual size of the db file to the VFS layer.
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
** safe to write into the database. Frames beyond mxSafeFrame might
|
||||
** overwrite database pages that are in use by active readers and thus
|
||||
** cannot be backfilled from the WAL.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nReq = ((i64)mxPage * szPage);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file. */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
|
||||
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
iOffset = (iDbpage-1)*(i64)szPage;
|
||||
testcase( IS_BIG_INT(iOffset) );
|
||||
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
|
||||
/* If work was actually accomplished... */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
|
||||
i64 szDb = pWal->hdr.nPage*(i64)szPage;
|
||||
testcase( IS_BIG_INT(szDb) );
|
||||
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
|
||||
if( rc==SQLITE_OK && sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = pInfo->aReadMark[i];
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y;
|
||||
xBusy = 0;
|
||||
}else{
|
||||
goto walcheckpoint_out;
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->nBackfill = mxSafeFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the reader lock held while backfilling */
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
|
||||
}
|
||||
if( pInfo->nBackfill<mxSafeFrame
|
||||
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
|
||||
){
|
||||
i64 nSize; /* Current size of database file */
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
|
||||
if( rc==SQLITE_BUSY ){
|
||||
/* Reset the return code so as not to report a checkpoint failure
|
||||
** just because there are active readers. */
|
||||
rc = SQLITE_OK;
|
||||
/* Sync the WAL to disk */
|
||||
if( sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
|
||||
}
|
||||
|
||||
/* If the database may grow as a result of this checkpoint, hint
|
||||
** about the eventual size of the db file to the VFS layer.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
i64 nReq = ((i64)mxPage * szPage);
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
||||
if( rc==SQLITE_OK && nSize<nReq ){
|
||||
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Iterate through the contents of the WAL, copying data to the db file */
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
|
||||
continue;
|
||||
}
|
||||
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
|
||||
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
|
||||
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
iOffset = (iDbpage-1)*(i64)szPage;
|
||||
testcase( IS_BIG_INT(iOffset) );
|
||||
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
|
||||
/* If work was actually accomplished... */
|
||||
if( rc==SQLITE_OK ){
|
||||
if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
|
||||
i64 szDb = pWal->hdr.nPage*(i64)szPage;
|
||||
testcase( IS_BIG_INT(szDb) );
|
||||
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
|
||||
if( rc==SQLITE_OK && sync_flags ){
|
||||
rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
pInfo->nBackfill = mxSafeFrame;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the reader lock held while backfilling */
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_BUSY ){
|
||||
/* Reset the return code so as not to report a checkpoint failure
|
||||
** just because there are active readers. */
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
|
||||
@ -1820,7 +1823,7 @@ static int walCheckpoint(
|
||||
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
|
||||
u32 salt1;
|
||||
sqlite3_randomness(4, &salt1);
|
||||
assert( mxSafeFrame==pWal->hdr.mxFrame );
|
||||
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
|
@ -208,5 +208,77 @@ do_select_tests 6.2 {
|
||||
{{ZZZthe hand XXXgesturesYYY (called beatsZZZ}}
|
||||
}
|
||||
|
||||
# Test some range queries on the rowid field.
|
||||
#
|
||||
do_execsql_test 7.1 {
|
||||
CREATE VIRTUAL TABLE ft4 USING fts4(x);
|
||||
CREATE TABLE t4(x);
|
||||
}
|
||||
|
||||
set SMALLINT -9223372036854775808
|
||||
set LARGEINT 9223372036854775807
|
||||
do_test 7.2 {
|
||||
db transaction {
|
||||
foreach {iFirst nEntry} [subst {
|
||||
0 100
|
||||
$SMALLINT 100
|
||||
[expr $LARGEINT - 99] 100
|
||||
}] {
|
||||
for {set i 0} {$i < $nEntry} {incr i} {
|
||||
set iRowid [expr $i + $iFirst]
|
||||
execsql {
|
||||
INSERT INTO ft4(rowid, x) VALUES($iRowid, 'x y z');
|
||||
INSERT INTO t4(rowid, x) VALUES($iRowid, 'x y z');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} {}
|
||||
|
||||
foreach {tn iFirst iLast} [subst {
|
||||
1 5 10
|
||||
2 $SMALLINT [expr $SMALLINT+5]
|
||||
3 $SMALLINT [expr $SMALLINT+50]
|
||||
4 [expr $LARGEINT-5] $LARGEINT
|
||||
5 $LARGEINT $LARGEINT
|
||||
6 $SMALLINT $LARGEINT
|
||||
7 $SMALLINT $SMALLINT
|
||||
8 $LARGEINT $SMALLINT
|
||||
}] {
|
||||
set res [db eval {
|
||||
SELECT rowid FROM t4 WHERE rowid BETWEEN $iFirst AND $iLast
|
||||
} ]
|
||||
|
||||
do_execsql_test 7.2.$tn.1.[llength $res] {
|
||||
SELECT rowid FROM ft4 WHERE rowid BETWEEN $iFirst AND $iLast
|
||||
} $res
|
||||
do_execsql_test 7.2.$tn.2.[llength $res] {
|
||||
SELECT rowid FROM ft4 WHERE rowid BETWEEN $iFirst AND $iLast
|
||||
ORDER BY rowid DESC
|
||||
} [lsort -decr -integer $res]
|
||||
}
|
||||
|
||||
foreach ii [db eval {SELECT rowid FROM t4}] {
|
||||
set res1 [db eval {SELECT rowid FROM t4 WHERE rowid > $ii}]
|
||||
set res2 [db eval {SELECT rowid FROM t4 WHERE rowid < $ii}]
|
||||
|
||||
do_execsql_test 7.3.$ii.1 {
|
||||
SELECT rowid FROM ft4 WHERE rowid > $ii
|
||||
} $res1
|
||||
|
||||
do_execsql_test 7.3.$ii.2 {
|
||||
SELECT rowid FROM ft4 WHERE rowid < $ii
|
||||
} $res2
|
||||
|
||||
do_execsql_test 7.3.$ii.3 {
|
||||
SELECT rowid FROM ft4 WHERE rowid > $ii ORDER BY rowid DESC
|
||||
} [lsort -integer -decr $res1]
|
||||
|
||||
do_execsql_test 7.3.$ii.4 {
|
||||
SELECT rowid FROM ft4 WHERE rowid < $ii ORDER BY rowid DESC
|
||||
} [lsort -integer -decr $res2]
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
@ -520,5 +520,24 @@ do_execsql_test 2.6 {
|
||||
{[one] two three [four] five}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 3 {
|
||||
CREATE VIRTUAL TABLE t3 USING fts4;
|
||||
INSERT INTO t3 VALUES('[one two three]');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'one';
|
||||
} {{[<b>one</b> two three]}}
|
||||
do_execsql_test 3.2 {
|
||||
SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'two';
|
||||
} {{[one <b>two</b> three]}}
|
||||
do_execsql_test 3.3 {
|
||||
SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'three';
|
||||
} {{[one two <b>three</b>]}}
|
||||
do_execsql_test 3.4 {
|
||||
SELECT snippet(t3) FROM t3 WHERE t3 MATCH 'one OR two OR three';
|
||||
} {{[<b>one</b> <b>two</b> <b>three</b>]}}
|
||||
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
finish_test
|
||||
|
||||
|
@ -125,5 +125,15 @@ do_test fuzz2-6.4b {
|
||||
db eval {SELECT quote(t) FROM t0}
|
||||
} {NULL}
|
||||
|
||||
# Another test case discovered by Michal Zalewski, this on on 2015-01-22.
|
||||
# Ticket 32b63d542433ca6757cd695aca42addf8ed67aa6
|
||||
#
|
||||
do_test fuzz2-7.1 {
|
||||
catchsql {select e.*,0 from(s,(L))e;}
|
||||
} {1 {no such table: s}}
|
||||
do_test fuzz2-7.2 {
|
||||
catchsql {SELECT c.* FROM (a,b) AS c}
|
||||
} {1 {no such table: a}}
|
||||
|
||||
|
||||
finish_test
|
||||
|
141
test/imposter1.test
Normal file
141
test/imposter1.test
Normal file
@ -0,0 +1,141 @@
|
||||
# 2015-01-30
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for SQLite library.
|
||||
#
|
||||
# The focus of this file is adding extra entries in the symbol table
|
||||
# using sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER) and verifying that
|
||||
# SQLite handles those as expected.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix imposter
|
||||
|
||||
# Create a bunch of data to sort against
|
||||
#
|
||||
do_test imposter-1.0 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d NOT NULL);
|
||||
CREATE INDEX t1b ON t1(b);
|
||||
CREATE UNIQUE INDEX t1c ON t1(c);
|
||||
WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b,c,d) SELECT i,1000+i,2000+i,3000+i FROM c;
|
||||
}
|
||||
set t1_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1'}]
|
||||
set t1b_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1b'}]
|
||||
set t1c_root [db one {SELECT rootpage FROM sqlite_master WHERE name='t1c'}]
|
||||
|
||||
# Create an imposter table that uses the same b-tree as t1 but which does
|
||||
# not have the indexes
|
||||
#
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $t1_root
|
||||
db eval {CREATE TABLE xt1(a,b,c,d)}
|
||||
|
||||
# And create an imposter table for the t1c index.
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 1 $t1c_root
|
||||
db eval {CREATE TABLE xt1c(c,rowid,PRIMARY KEY(c,rowid))WITHOUT ROWID;}
|
||||
|
||||
# Go out of imposter mode for now.
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 0
|
||||
|
||||
# Create triggers to record changes to xt1.
|
||||
#
|
||||
db eval {
|
||||
CREATE TEMP TABLE chnglog(desc TEXT);
|
||||
CREATE TEMP TRIGGER xt1_del AFTER DELETE ON xt1 BEGIN
|
||||
INSERT INTO chnglog VALUES(
|
||||
printf('DELETE t1: rowid=%d, a=%s, b=%s, c=%s, d=%s',
|
||||
old.rowid, quote(old.a), quote(old.b), quote(old.c),
|
||||
quote(old.d)));
|
||||
END;
|
||||
CREATE TEMP TRIGGER xt1_ins AFTER INSERT ON xt1 BEGIN
|
||||
INSERT INTO chnglog VALUES(
|
||||
printf('INSERT t1: rowid=%d, a=%s, b=%s, c=%s, d=%s',
|
||||
new.rowid, quote(new.a), quote(new.b), quote(new.c),
|
||||
quote(new.d)));
|
||||
END;
|
||||
}
|
||||
} {}
|
||||
|
||||
# The xt1 table has separate xt1.rowid and xt1.a columns. The xt1.rowid
|
||||
# column corresponds to t1.rowid and t1.a, but the xt1.a column is always
|
||||
# NULL
|
||||
#
|
||||
do_execsql_test imposter-1.1 {
|
||||
SELECT rowid FROM xt1 WHERE a IS NOT NULL;
|
||||
} {}
|
||||
do_execsql_test imposter-1.2 {
|
||||
SELECT a,b,c,d FROM t1 EXCEPT SELECT rowid,b,c,d FROM xt1;
|
||||
SELECT rowid,b,c,d FROM xt1 EXCEPT SELECT a,b,c,d FROM t1;
|
||||
} {}
|
||||
|
||||
|
||||
# Make changes via the xt1 shadow table. This will not update the
|
||||
# indexes on t1 nor check the uniqueness constraint on t1.c nor check
|
||||
# the NOT NULL constraint on t1.d, resulting in a logically inconsistent
|
||||
# database.
|
||||
#
|
||||
do_execsql_test imposter-1.3 {
|
||||
DELETE FROM xt1 WHERE rowid=5;
|
||||
INSERT INTO xt1(rowid,a,b,c,d) VALUES(99,'hello',1099,2022,NULL);
|
||||
SELECT * FROM chnglog ORDER BY rowid;
|
||||
} [list \
|
||||
{DELETE t1: rowid=5, a=NULL, b=1005, c=2005, d=3005} \
|
||||
{INSERT t1: rowid=99, a='hello', b=1099, c=2022, d=NULL} \
|
||||
]
|
||||
|
||||
do_execsql_test imposter-1.4a {
|
||||
PRAGMA integrity_check;
|
||||
} {/NULL value in t1.d/}
|
||||
do_execsql_test imposter-1.4b {
|
||||
PRAGMA integrity_check;
|
||||
} {/row # missing from index t1b/}
|
||||
do_execsql_test imposter-1.4c {
|
||||
PRAGMA integrity_check;
|
||||
} {/row # missing from index t1c/}
|
||||
|
||||
# Cleanup the corruption.
|
||||
# Then demonstrate that the xt1c imposter table can insert non-unique
|
||||
# and NULL values into the UNIQUE index.
|
||||
#
|
||||
do_execsql_test imposter-2.0 {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10)
|
||||
INSERT INTO t1(a,b,c,d) SELECT i,i,i,i FROM c;
|
||||
UPDATE xt1c SET c=NULL WHERE rowid=5;
|
||||
PRAGMA integrity_check;
|
||||
} {/row # missing from index t1c/}
|
||||
|
||||
do_execsql_test imposter-2.1 {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10)
|
||||
INSERT INTO t1(a,b,c,d) SELECT i,i,i,i FROM c;
|
||||
UPDATE xt1c SET c=99 WHERE rowid IN (5,7,9);
|
||||
SELECT c FROM t1 ORDER BY c;
|
||||
} {1 2 3 4 6 8 10 99 99 99}
|
||||
do_execsql_test imposter-2.2 {
|
||||
UPDATE xt1 SET c=99 WHERE rowid IN (5,7,9);
|
||||
PRAGMA integrity_check;
|
||||
} {/non-unique entry in index t1c/}
|
||||
|
||||
# Erase the imposter tables
|
||||
#
|
||||
do_test imposter-3.1 {
|
||||
sqlite3_test_control SQLITE_TESTCTRL_IMPOSTER db main 0 1
|
||||
db eval {
|
||||
DELETE FROM t1 WHERE rowid IN (5,7,9);
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
|
||||
|
||||
finish_test
|
@ -621,4 +621,14 @@ do_test misc1-19.2 {
|
||||
set fault_callbacks
|
||||
} {0}
|
||||
|
||||
# 2015-01-26: Valgrind-detected over-read.
|
||||
# Reported on sqlite-users@sqlite.org by Michal Zalewski. Found by afl-fuzz
|
||||
# presumably.
|
||||
#
|
||||
do_execsql_test misc1-20.1 {
|
||||
CREATE TABLE t0(x INTEGER DEFAULT(0==0) NOT NULL);
|
||||
REPLACE INTO t0(x) VALUES('');
|
||||
SELECT rowid, quote(x) FROM t0;
|
||||
} {1 ''}
|
||||
|
||||
finish_test
|
||||
|
@ -390,6 +390,87 @@ foreach {testprefix do_wal_checkpoint} {
|
||||
} [wal_file_size 2 1024]
|
||||
|
||||
}
|
||||
|
||||
# Test that FULL, RESTART and TRUNCATE callbacks block on other clients
|
||||
# and truncate the wal file as required even if the entire wal file has
|
||||
# already been checkpointed when they are invoked.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
|
||||
code1 $do_wal_checkpoint
|
||||
code2 $do_wal_checkpoint
|
||||
code3 $do_wal_checkpoint
|
||||
|
||||
do_test 5.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA auto_vacuum = 0;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = normal;
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX i1 ON t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
}
|
||||
file size test.db-wal
|
||||
} [wal_file_size 10 1024]
|
||||
|
||||
do_test 5.$tn.2 {
|
||||
sql2 { BEGIN; SELECT * FROM t1 }
|
||||
} {1 2 3 4 5 6}
|
||||
|
||||
do_test 5.$tn.3 { do_wal_checkpoint db -mode passive } {0 10 10}
|
||||
|
||||
do_test 5.$tn.4 {
|
||||
sql3 { BEGIN; INSERT INTO t1 VALUES(7, 8); }
|
||||
} {}
|
||||
|
||||
do_test 5.$tn.5 { do_wal_checkpoint db -mode passive } {0 10 10}
|
||||
do_test 5.$tn.6 { do_wal_checkpoint db -mode full } {1 10 10}
|
||||
|
||||
do_test 5.$tn.7 { sql3 { ROLLBACK } } {}
|
||||
|
||||
do_test 5.$tn.8 { do_wal_checkpoint db -mode full } {0 10 10}
|
||||
do_test 5.$tn.9 { do_wal_checkpoint db -mode truncate } {1 10 10}
|
||||
|
||||
do_test 5.$tn.10 {
|
||||
file size test.db-wal
|
||||
} [wal_file_size 10 1024]
|
||||
|
||||
proc xBusyHandler {n} { sql2 { COMMIT } ; return 0 }
|
||||
db busy xBusyHandler
|
||||
|
||||
do_test 5.$tn.11 { do_wal_checkpoint db -mode truncate } {0 0 0}
|
||||
do_test 5.$tn.12 { file size test.db-wal } 0
|
||||
|
||||
do_test 5.$tn.13 {
|
||||
sql1 {
|
||||
INSERT INTO t1 VALUES(7, 8);
|
||||
INSERT INTO t1 VALUES(9, 10);
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2 3 4 5 6 7 8 9 10}
|
||||
|
||||
do_test 5.$tn.14 {
|
||||
sql2 { BEGIN; SELECT * FROM t1 }
|
||||
} {1 2 3 4 5 6 7 8 9 10}
|
||||
|
||||
proc xBusyHandler {n} { return 1 }
|
||||
do_test 5.$tn.15 { do_wal_checkpoint db -mode truncate } {1 4 4}
|
||||
do_test 5.$tn.16 { file size test.db-wal } [wal_file_size 4 1024]
|
||||
|
||||
do_test 5.$tn.17 { do_wal_checkpoint db -mode restart } {1 4 4}
|
||||
|
||||
proc xBusyHandler {n} { sql2 { COMMIT } ; return 0 }
|
||||
db busy xBusyHandler
|
||||
do_test 5.$tn.18 { do_wal_checkpoint db -mode restart } {0 4 4}
|
||||
do_test 5.$tn.19 { file size test.db-wal } [wal_file_size 4 1024]
|
||||
|
||||
do_test 5.$tn.20 { do_wal_checkpoint db -mode truncate } {0 0 0}
|
||||
do_test 5.$tn.21 { file size test.db-wal } 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user