Merge latest trunk changes with this branch.

FossilOrigin-Name: 76212f2c9a3c3ff0e238d6dad776938c6af674e6
This commit is contained in:
dan 2015-02-02 09:40:36 +00:00
commit 32348f7bd2
23 changed files with 656 additions and 241 deletions

View File

@ -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

View File

@ -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;

View File

@ -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.
*/

View File

@ -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;
}

View File

@ -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

View File

@ -1 +1 @@
1fffe51fa92f1784365140d5b163ab6c690981ae
76212f2c9a3c3ff0e238d6dad776938c6af674e6

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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 ){

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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
View File

@ -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 ){

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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

View File

@ -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
}
}