Fix various problems in fts5 revealed by fault-injection tests.

FossilOrigin-Name: e358c3de5c916f2c851ab9324ceaae4e4e7a0fbd
This commit is contained in:
dan
2014-12-18 18:25:48 +00:00
parent 845d0ab323
commit e4bec37900
9 changed files with 317 additions and 195 deletions
+1 -1
View File
@@ -223,7 +223,7 @@ static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
break;
case FTS5_ROLLBACK:
assert( p->ts.eState==1 || p->ts.eState==2 );
assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 );
p->ts.eState = 0;
break;
+11 -8
View File
@@ -74,14 +74,17 @@ static int fts5ConfigParseSpecial(
char **pzErr /* OUT: Error message */
){
if( sqlite3_stricmp(zCmd, "prefix")==0 ){
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
int rc = SQLITE_OK;
char *p;
if( pConfig->aPrefix ){
*pzErr = sqlite3_mprintf("multiple prefix=... directives");
return SQLITE_ERROR;
rc = SQLITE_ERROR;
}else{
pConfig->aPrefix = sqlite3Fts5MallocZero(&rc, nByte);
}
pConfig->aPrefix = sqlite3_malloc(sizeof(int) * FTS5_MAX_PREFIX_INDEXES);
p = zArg;
while( p[0] ){
while( rc==SQLITE_OK && p[0] ){
int nPre = 0;
while( p[0]==' ' ) p++;
while( p[0]>='0' && p[0]<='9' && nPre<1000 ){
@@ -93,16 +96,16 @@ static int fts5ConfigParseSpecial(
p++;
}else if( p[0] ){
*pzErr = sqlite3_mprintf("malformed prefix=... directive");
return SQLITE_ERROR;
rc = SQLITE_ERROR;
}
if( nPre==0 || nPre>=1000 ){
if( rc==SQLITE_OK && (nPre==0 || nPre>=1000) ){
*pzErr = sqlite3_mprintf("prefix length out of range: %d", nPre);
return SQLITE_ERROR;
rc = SQLITE_ERROR;
}
pConfig->aPrefix[pConfig->nPrefix] = nPre;
pConfig->nPrefix++;
}
return SQLITE_OK;
return rc;
}
*pzErr = sqlite3_mprintf("unrecognized directive: \"%s\"", zCmd);
@@ -191,7 +194,7 @@ int sqlite3Fts5ConfigParse(
}
/* If it is not a special directive, it must be a column name. In
** this case, check that it is not the reserved column name "rank". */
** this case, check that it is not the reserved column name "rank". */
if( zDup ){
sqlite3Fts5Dequote(zDup);
pRet->azCol[pRet->nCol++] = zDup;
+16 -9
View File
@@ -213,6 +213,7 @@ int sqlite3Fts5ExprNew(
*ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr));
if( pNew==0 ){
sParse.rc = SQLITE_NOMEM;
sqlite3Fts5ParseNodeFree(sParse.pExpr);
}else{
pNew->pRoot = sParse.pExpr;
pNew->pIndex = 0;
@@ -771,7 +772,8 @@ static int fts5ExprNearInitAll(
(pExpr->bAsc ? FTS5INDEX_QUERY_ASC : 0),
&pTerm->pIter
);
if( pTerm->pIter && sqlite3Fts5IterEof(pTerm->pIter) ){
assert( rc==SQLITE_OK || pTerm->pIter==0 );
if( pTerm->pIter==0 || sqlite3Fts5IterEof(pTerm->pIter) ){
pNode->bEof = 1;
break;
}
@@ -1204,24 +1206,29 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
int rc; /* Tokenize return code */
char *z = 0;
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pPhrase;
if( pPhrase==0 ){
if( (pParse->nPhrase % 8)==0 ){
int nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
Fts5ExprPhrase **apNew;
apNew = (Fts5ExprPhrase**)sqlite3_realloc(pParse->apPhrase, nByte);
if( apNew==0 ) return 0;
if( apNew==0 ){
pParse->rc = SQLITE_NOMEM;
fts5ExprPhraseFree(pPhrase);
return 0;
}
pParse->apPhrase = apNew;
}
pParse->nPhrase++;
}
pParse->rc = fts5ParseStringFromToken(pToken, &z);
if( z==0 ) return 0;
sqlite3Fts5Dequote(z);
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pPhrase;
rc = sqlite3Fts5Tokenize(pConfig, z, strlen(z), &sCtx, fts5ParseTokenize);
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
sqlite3Fts5Dequote(z);
rc = sqlite3Fts5Tokenize(pConfig, z, strlen(z), &sCtx, fts5ParseTokenize);
}
if( rc ){
pParse->rc = rc;
fts5ExprPhraseFree(sCtx.pPhrase);
+185 -158
View File
@@ -602,13 +602,14 @@ static u16 fts5GetU16(const u8 *aIn){
** the Fts5Index handle passed as the first argument.
*/
static void *fts5IdxMalloc(Fts5Index *p, int nByte){
void *pRet;
assert( p->rc==SQLITE_OK );
pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
p->rc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
void *pRet = 0;
if( p->rc==SQLITE_OK ){
pRet = sqlite3_malloc(nByte);
if( pRet==0 ){
p->rc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
}
}
return pRet;
}
@@ -662,8 +663,9 @@ static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
*/
static void fts5CloseReader(Fts5Index *p){
if( p->pReader ){
sqlite3_blob_close(p->pReader);
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
sqlite3_blob_close(pReader);
}
}
@@ -707,9 +709,10 @@ sqlite3_free(buf.p);
int nByte = sqlite3_blob_bytes(p->pReader);
if( pBuf ){
fts5BufferZero(pBuf);
fts5BufferGrow(&rc, pBuf, nByte);
rc = sqlite3_blob_read(p->pReader, pBuf->p, nByte, 0);
if( rc==SQLITE_OK ) pBuf->n = nByte;
if( SQLITE_OK==fts5BufferGrow(&rc, pBuf, nByte) ){
rc = sqlite3_blob_read(p->pReader, pBuf->p, nByte, 0);
if( rc==SQLITE_OK ) pBuf->n = nByte;
}
}else{
pRet = (Fts5Data*)fts5IdxMalloc(p, sizeof(Fts5Data) + nByte);
if( !pRet ) return 0;
@@ -854,6 +857,20 @@ static void fts5DataRemoveSegment(Fts5Index *p, int iIdx, int iSegid){
fts5DataDelete(p, iFirst, iLast);
}
/*
** Release a reference to an Fts5Structure object returned by an earlier
** call to fts5StructureRead() or fts5StructureDecode().
*/
static void fts5StructureRelease(Fts5Structure *pStruct){
if( pStruct ){
int i;
for(i=0; i<pStruct->nLevel; i++){
sqlite3_free(pStruct->aLevel[i].aSeg);
}
sqlite3_free(pStruct);
}
}
/*
** Deserialize and return the structure record currently stored in serialized
** form within buffer pData/nData.
@@ -918,6 +935,9 @@ static int fts5StructureDecode(
i += getVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoFirst);
i += getVarint32(&pData[i], pLvl->aSeg[iSeg].pgnoLast);
}
}else{
fts5StructureRelease(pRet);
pRet = 0;
}
}
}
@@ -1009,19 +1029,11 @@ static Fts5Structure *fts5StructureRead(Fts5Index *p, int iIdx){
}
fts5DataRelease(pData);
return pRet;
}
/*
** Release a reference to an Fts5Structure object returned by an earlier
** call to fts5StructureRead() or fts5StructureDecode().
*/
static void fts5StructureRelease(Fts5Structure *pStruct){
int i;
for(i=0; i<pStruct->nLevel; i++){
sqlite3_free(pStruct->aLevel[i].aSeg);
if( p->rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
pRet = 0;
}
sqlite3_free(pStruct);
return pRet;
}
/*
@@ -1045,40 +1057,42 @@ static int fts5StructureCountSegments(Fts5Structure *pStruct){
** error has already occurred, this function is a no-op.
*/
static void fts5StructureWrite(Fts5Index *p, int iIdx, Fts5Structure *pStruct){
int nSegment; /* Total number of segments */
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
if( p->rc==SQLITE_OK ){
int nSegment; /* Total number of segments */
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
nSegment = fts5StructureCountSegments(pStruct);
memset(&buf, 0, sizeof(Fts5Buffer));
nSegment = fts5StructureCountSegments(pStruct);
memset(&buf, 0, sizeof(Fts5Buffer));
/* Append the current configuration cookie */
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
fts5BufferAppend32(&p->rc, &buf, iCookie);
/* Append the current configuration cookie */
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
fts5BufferAppend32(&p->rc, &buf, iCookie);
fts5BufferAppendVarint(&p->rc, &buf, pStruct->nLevel);
fts5BufferAppendVarint(&p->rc, &buf, nSegment);
fts5BufferAppendVarint(&p->rc, &buf, (i64)pStruct->nWriteCounter);
fts5BufferAppendVarint(&p->rc, &buf, pStruct->nLevel);
fts5BufferAppendVarint(&p->rc, &buf, nSegment);
fts5BufferAppendVarint(&p->rc, &buf, (i64)pStruct->nWriteCounter);
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
int iSeg; /* Used to iterate through segments */
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg);
assert( pLvl->nMerge<=pLvl->nSeg );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
int iSeg; /* Used to iterate through segments */
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
fts5BufferAppendVarint(&p->rc, &buf, pLvl->nMerge);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->nSeg);
assert( pLvl->nMerge<=pLvl->nSeg );
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].nHeight);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].nHeight);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
}
}
}
fts5DataWrite(p, FTS5_STRUCTURE_ROWID(iIdx), buf.p, buf.n);
fts5BufferFree(&buf);
fts5DataWrite(p, FTS5_STRUCTURE_ROWID(iIdx), buf.p, buf.n);
fts5BufferFree(&buf);
}
}
#if 0
@@ -1864,7 +1878,7 @@ static void fts5SegIterSeekInit(
res = fts5BufferCompareBlob(&pIter->term, pTerm, nTerm);
if( res>=0 ) break;
fts5SegIterNext(p, pIter);
}while( pIter->pLeaf );
}while( pIter->pLeaf && p->rc==SQLITE_OK );
if( bGe==0 && res ){
/* Set iterator to point to EOF */
@@ -1873,7 +1887,7 @@ static void fts5SegIterSeekInit(
}
}
if( bGe==0 ){
if( p->rc==SQLITE_OK && bGe==0 ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_ASC ){
@@ -2422,7 +2436,7 @@ static void fts5IndexDiscardData(Fts5Index *p){
Fts5Config *pConfig = p->pConfig;
int i;
for(i=0; i<=pConfig->nPrefix; i++){
sqlite3Fts5HashClear(p->apHash[i]);
if( p->apHash[i] ) sqlite3Fts5HashClear(p->apHash[i]);
}
p->nPendingData = 0;
}
@@ -2609,8 +2623,8 @@ static void fts5WriteAppendTerm(
int nPrefix; /* Bytes of prefix compression for term */
Fts5PageWriter *pPage = &pWriter->aWriter[0];
assert( pPage->buf.n==0 || pPage->buf.n>4 );
if( pPage->buf.n==0 ){
assert( pPage==0 || pPage->buf.n==0 || pPage->buf.n>4 );
if( pPage && pPage->buf.n==0 ){
/* Zero the first term and first docid fields */
static const u8 zero[] = { 0x00, 0x00, 0x00, 0x00 };
fts5BufferAppendBlob(&p->rc, &pPage->buf, 4, zero);
@@ -2660,30 +2674,32 @@ static void fts5WriteAppendRowid(
Fts5SegWriter *pWriter,
i64 iRowid
){
Fts5PageWriter *pPage = &pWriter->aWriter[0];
if( p->rc==SQLITE_OK ){
Fts5PageWriter *pPage = &pWriter->aWriter[0];
/* If this is to be the first docid written to the page, set the
** docid-pointer in the page-header. Also append a value to the dlidx
** buffer, in case a doclist-index is required. */
if( pWriter->bFirstRowidInPage ){
fts5PutU16(pPage->buf.p, pPage->buf.n);
fts5WriteDlidxAppend(p, pWriter, iRowid);
}
/* If this is to be the first docid written to the page, set the
** docid-pointer in the page-header. Also append a value to the dlidx
** buffer, in case a doclist-index is required. */
if( pWriter->bFirstRowidInPage ){
fts5PutU16(pPage->buf.p, pPage->buf.n);
fts5WriteDlidxAppend(p, pWriter, iRowid);
}
/* Write the docid. */
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert( iRowid<pWriter->iPrevRowid );
fts5BufferAppendVarint(&p->rc, &pPage->buf, pWriter->iPrevRowid - iRowid);
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
pWriter->bFirstRowidInPage = 0;
/* Write the docid. */
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert( p->rc || iRowid<pWriter->iPrevRowid );
fts5BufferAppendVarint(&p->rc, &pPage->buf, pWriter->iPrevRowid - iRowid);
}
pWriter->iPrevRowid = iRowid;
pWriter->bFirstRowidInDoclist = 0;
pWriter->bFirstRowidInPage = 0;
if( pPage->buf.n>=p->pConfig->pgsz ){
fts5WriteFlushLeaf(p, pWriter);
pWriter->bFirstRowidInPage = 1;
if( pPage->buf.n>=p->pConfig->pgsz ){
fts5WriteFlushLeaf(p, pWriter);
pWriter->bFirstRowidInPage = 1;
}
}
}
@@ -2692,11 +2708,13 @@ static void fts5WriteAppendPoslistInt(
Fts5SegWriter *pWriter,
int iVal
){
Fts5PageWriter *pPage = &pWriter->aWriter[0];
fts5BufferAppendVarint(&p->rc, &pPage->buf, iVal);
if( pPage->buf.n>=p->pConfig->pgsz ){
fts5WriteFlushLeaf(p, pWriter);
pWriter->bFirstRowidInPage = 1;
if( p->rc==SQLITE_OK ){
Fts5PageWriter *pPage = &pWriter->aWriter[0];
fts5BufferAppendVarint(&p->rc, &pPage->buf, iVal);
if( pPage->buf.n>=p->pConfig->pgsz ){
fts5WriteFlushLeaf(p, pWriter);
pWriter->bFirstRowidInPage = 1;
}
}
}
@@ -2744,32 +2762,37 @@ static void fts5WriteFinish(
int *pnLeaf /* OUT: Number of leaf pages in b-tree */
){
int i;
*pnLeaf = pWriter->aWriter[0].pgno;
if( *pnLeaf==1 && pWriter->aWriter[0].buf.n==0 ){
*pnLeaf = 0;
*pnHeight = 0;
}else{
fts5WriteFlushLeaf(p, pWriter);
if( pWriter->nWriter==1 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){
fts5WriteBtreeGrow(p, pWriter);
}
if( pWriter->nWriter>1 ){
fts5WriteBtreeNEmpty(p, pWriter);
}
*pnHeight = pWriter->nWriter;
if( p->rc==SQLITE_OK ){
*pnLeaf = pWriter->aWriter[0].pgno;
if( *pnLeaf==1 && pWriter->aWriter[0].buf.n==0 ){
*pnLeaf = 0;
*pnHeight = 0;
}else{
fts5WriteFlushLeaf(p, pWriter);
if( pWriter->nWriter==1 && pWriter->nEmpty>=FTS5_MIN_DLIDX_SIZE ){
fts5WriteBtreeGrow(p, pWriter);
}
if( pWriter->nWriter>1 ){
fts5WriteBtreeNEmpty(p, pWriter);
}
*pnHeight = pWriter->nWriter;
for(i=1; i<pWriter->nWriter; i++){
Fts5PageWriter *pPg = &pWriter->aWriter[i];
fts5DataWrite(p,
FTS5_SEGMENT_ROWID(pWriter->iIdx, pWriter->iSegid, i, pPg->pgno),
pPg->buf.p, pPg->buf.n
);
for(i=1; i<pWriter->nWriter; i++){
Fts5PageWriter *pPg = &pWriter->aWriter[i];
fts5DataWrite(p,
FTS5_SEGMENT_ROWID(pWriter->iIdx, pWriter->iSegid, i, pPg->pgno),
pPg->buf.p, pPg->buf.n
);
}
}
}
for(i=0; i<pWriter->nWriter; i++){
Fts5PageWriter *pPg = &pWriter->aWriter[i];
fts5BufferFree(&pPg->term);
fts5BufferFree(&pPg->buf);
assert( pPg || p->rc!=SQLITE_OK );
if( pPg ){
fts5BufferFree(&pPg->term);
fts5BufferFree(&pPg->buf);
}
}
sqlite3_free(pWriter->aWriter);
sqlite3Fts5BufferFree(&pWriter->dlidx);
@@ -3025,55 +3048,57 @@ static void fts5IndexWork(
Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
int nLeaf /* Number of output leaves just written */
){
Fts5Structure *pStruct = *ppStruct;
i64 nWrite; /* Initial value of write-counter */
int nWork; /* Number of work-quanta to perform */
int nRem; /* Number of leaf pages left to write */
if( p->rc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
i64 nWrite; /* Initial value of write-counter */
int nWork; /* Number of work-quanta to perform */
int nRem; /* Number of leaf pages left to write */
/* Update the write-counter. While doing so, set nWork. */
nWrite = pStruct->nWriteCounter;
nWork = ((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit);
pStruct->nWriteCounter += nLeaf;
nRem = p->nWorkUnit * nWork * pStruct->nLevel;
/* Update the write-counter. While doing so, set nWork. */
nWrite = pStruct->nWriteCounter;
nWork = ((nWrite + nLeaf) / p->nWorkUnit) - (nWrite / p->nWorkUnit);
pStruct->nWriteCounter += nLeaf;
nRem = p->nWorkUnit * nWork * pStruct->nLevel;
while( nRem>0 ){
int iLvl; /* To iterate through levels */
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
while( nRem>0 ){
int iLvl; /* To iterate through levels */
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
/* Set iBestLvl to the level to read input segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
nBest = pLvl->nMerge;
/* Set iBestLvl to the level to read input segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
nBest = pLvl->nMerge;
}
break;
}
if( pLvl->nSeg>nBest ){
nBest = pLvl->nSeg;
iBestLvl = iLvl;
}
break;
}
if( pLvl->nSeg>nBest ){
nBest = pLvl->nSeg;
iBestLvl = iLvl;
}
}
/* If nBest is still 0, then the index must be empty. */
/* If nBest is still 0, then the index must be empty. */
#ifdef SQLITE_DEBUG
for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
assert( pStruct->aLevel[iLvl].nSeg==0 );
}
for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
assert( pStruct->aLevel[iLvl].nSeg==0 );
}
#endif
if( nBest<p->pConfig->nAutomerge
&& pStruct->aLevel[iBestLvl].nMerge==0
){
break;
if( nBest<p->pConfig->nAutomerge
&& pStruct->aLevel[iBestLvl].nMerge==0
){
break;
}
fts5IndexMergeLevel(p, iIdx, &pStruct, iBestLvl, &nRem);
fts5StructurePromote(p, iBestLvl+1, pStruct);
assert( nRem==0 || p->rc==SQLITE_OK );
*ppStruct = pStruct;
}
fts5IndexMergeLevel(p, iIdx, &pStruct, iBestLvl, &nRem);
fts5StructurePromote(p, iBestLvl+1, pStruct);
assert( nRem==0 || p->rc==SQLITE_OK );
*ppStruct = pStruct;
}
}
@@ -3123,17 +3148,17 @@ static int fts5FlushNewEntry(
int nPoslist
){
Fts5FlushCtx *p = (Fts5FlushCtx*)pCtx;
int rc = SQLITE_OK;
Fts5Index *pIdx = p->pIdx;
/* Append the rowid itself */
fts5WriteAppendRowid(p->pIdx, &p->writer, iRowid);
fts5WriteAppendRowid(pIdx, &p->writer, iRowid);
/* Append the size of the position list in bytes */
fts5WriteAppendPoslistInt(p->pIdx, &p->writer, nPoslist);
fts5WriteAppendPoslistInt(pIdx, &p->writer, nPoslist);
/* And the poslist data */
fts5WriteAppendPoslistData(p->pIdx, &p->writer, aPoslist, nPoslist);
return rc;
fts5WriteAppendPoslistData(pIdx, &p->writer, aPoslist, nPoslist);
return pIdx->rc;
}
/*
@@ -3485,20 +3510,22 @@ static void fts5MultiIterPoslist(
int bSz,
Fts5Buffer *pBuf
){
Fts5ChunkIter iter;
Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1] ];
assert( fts5MultiIterEof(p, pMulti)==0 );
fts5ChunkIterInit(p, pSeg, &iter);
if( fts5ChunkIterEof(p, &iter)==0 ){
if( bSz ){
fts5BufferAppendVarint(&p->rc, pBuf, iter.nRem);
}
while( fts5ChunkIterEof(p, &iter)==0 ){
fts5BufferAppendBlob(&p->rc, pBuf, iter.n, iter.p);
fts5ChunkIterNext(p, &iter);
if( p->rc==SQLITE_OK ){
Fts5ChunkIter iter;
Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1] ];
assert( fts5MultiIterEof(p, pMulti)==0 );
fts5ChunkIterInit(p, pSeg, &iter);
if( fts5ChunkIterEof(p, &iter)==0 ){
if( bSz ){
fts5BufferAppendVarint(&p->rc, pBuf, iter.nRem);
}
while( fts5ChunkIterEof(p, &iter)==0 ){
fts5BufferAppendBlob(&p->rc, pBuf, iter.n, iter.p);
fts5ChunkIterNext(p, &iter);
}
}
fts5ChunkIterRelease(&iter);
}
fts5ChunkIterRelease(&iter);
}
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
+12 -12
View File
@@ -1,5 +1,5 @@
C Begin\stesting\sfts5\sOOM\sand\sIO\serror\shandling.
D 2014-12-03T17:27:35.105
C Fix\svarious\sproblems\sin\sfts5\srevealed\sby\sfault-injection\stests.
D 2014-12-18T18:25:48.377
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -104,15 +104,15 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
F ext/fts5/extract_api_docs.tcl 6320db4a1d0722a4e2069e661381ad75e9889786
F ext/fts5/fts5.c 1dae34f4a788b5760c52b914d6384d83ee027b35
F ext/fts5/fts5.c d1c1722eb661da3e8e3a19909958b97beff7d243
F ext/fts5/fts5.h 72fc1e9995b1ddc254a487b9528614a83bd3dfb6
F ext/fts5/fts5Int.h 36054b1dfc4881a9b94f945b348ab6cc01c0c7a5
F ext/fts5/fts5_aux.c 0e3e5fea6bf5772805afe14c95cb5f16e03e4b3f
F ext/fts5/fts5_buffer.c 1bc5c762bb2e9b4a40b2e8a820a31b809e72eec1
F ext/fts5/fts5_config.c 17986112dc76e7e39170e08df68f84180f66a9fe
F ext/fts5/fts5_expr.c 5db50cd4ae9c3764d7daa8388bf406c0bad15039
F ext/fts5/fts5_config.c 5caeb4e77680d635be25b899f97a29cf26fb45ce
F ext/fts5/fts5_expr.c 27d3d2deebae277c34ae2bb3d501dd879c442ba5
F ext/fts5/fts5_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
F ext/fts5/fts5_index.c 9233b8b1f519e50d9ec139031032d9211dfcb541
F ext/fts5/fts5_index.c 13b6d002e10840d8ec525ccd4a2bfc8831ea7a47
F ext/fts5/fts5_storage.c bfeedb83b095a1018f4f531c3cc3f9099e9f9081
F ext/fts5/fts5_tcl.c 5272224faf9be129679da5e19d788f0307afc375
F ext/fts5/fts5_tokenize.c 8360c0d1ae0d4696f3cc13f7c67a2db6011cdc5b
@@ -306,7 +306,7 @@ F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
F src/vdbesort.c 44441d73b08b3a638dcdb725afffb87c6574ad27
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/vtab.c b05a86bed6ee2c7f79edb2cb57b951b220867caf
F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
@@ -612,7 +612,7 @@ F test/fts5aj.test bc3d91bd012c7ca175cdf266c2074920bb5fa5ba
F test/fts5ak.test e55bb0f3fac1291d32bc9485a3ee55a7d76f4d5f
F test/fts5al.test 61b067f3b0b61679ab164a8a855882dfd313988d
F test/fts5ea.test afaf3497b43add578384dc1fd26b0342738abe87
F test/fts5fault1.test 27cb71251f8f2cd710ce4bdc1f0c29fa5db83be7
F test/fts5fault1.test 6fef96cf6eccd9b9fc9f4518cc15c4fa9740ef66
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@@ -722,7 +722,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 58e54229c4132ef882a11fab6419ec4cd3073589
F test/malloc_common.tcl dc07e2bbbfc3f8416f4cbddcc139d77eb360d9af
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test fcb5297b321b562084fc79d64d5a12a1cd2b639b
@@ -1208,7 +1208,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 b5f5971283b9b2f60c16f9675099855af95012cd
R cb30a6b5c5f7ea511cc1ede93a5d038a
P 2037dba62fdd995ad15b642abe499a790f5ffe5c
R 701ca9549e5d1bd70b92dde1949b5886
U dan
Z f7fa77a51653f0fa8e3497900e76f571
Z d83a5deacda027d17d377616a8122fa0
+1 -1
View File
@@ -1 +1 @@
2037dba62fdd995ad15b642abe499a790f5ffe5c
e358c3de5c916f2c851ab9324ceaae4e4e7a0fbd
+4 -3
View File
@@ -789,8 +789,10 @@ int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){
static void callFinaliser(sqlite3 *db, int offset){
int i;
if( db->aVTrans ){
VTable **aVTrans = db->aVTrans;
db->aVTrans = 0;
for(i=0; i<db->nVTrans; i++){
VTable *pVTab = db->aVTrans[i];
VTable *pVTab = aVTrans[i];
sqlite3_vtab *p = pVTab->pVtab;
if( p ){
int (*x)(sqlite3_vtab *);
@@ -800,9 +802,8 @@ static void callFinaliser(sqlite3 *db, int offset){
pVTab->iSavepoint = 0;
sqlite3VtabUnlock(pVTab);
}
sqlite3DbFree(db, db->aVTrans);
sqlite3DbFree(db, aVTrans);
db->nVTrans = 0;
db->aVTrans = 0;
}
}
+75 -1
View File
@@ -23,15 +23,89 @@ ifcapable !fts5 {
return
}
# Simple tests:
#
# 1: CREATE VIRTUAL TABLE
# 2: INSERT statement
# 3: DELETE statement
# 4: MATCH expressions
#
if 1 {
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE VIRTUAL TABLE t1 USING fts5(a) }
execsql { CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3') }
} -test {
faultsim_test_result {0 {}}
}
reset_db
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3');
}
faultsim_save_and_close
do_faultsim_test 2 -prep {
faultsim_restore_and_reopen
} -body {
execsql {
INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno');
}
} -test {
faultsim_test_result {0 {}}
}
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, prefix='1, 2, 3');
INSERT INTO t1 VALUES('a b c', 'a bc def ghij klmno');
}
faultsim_save_and_close
do_faultsim_test 3 -prep {
faultsim_restore_and_reopen
} -body {
execsql { DELETE FROM t1 }
} -test {
faultsim_test_result {0 {}}
}
}
reset_db
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t2 USING fts5(a, b);
INSERT INTO t2 VALUES('m f a jj th q jr ar', 'hj n h h sg j i m');
INSERT INTO t2 VALUES('nr s t g od j kf h', 'sb h aq rg op rb n nl');
INSERT INTO t2 VALUES('do h h pb p p q fr', 'c rj qs or cr a l i');
INSERT INTO t2 VALUES('lk gp t i lq mq qm p', 'h mr g f op ld aj h');
INSERT INTO t2 VALUES('ct d sq kc qi k f j', 'sn gh c of g s qt q');
INSERT INTO t2 VALUES('d ea d d om mp s ab', 'dm hg l df cm ft pa c');
INSERT INTO t2 VALUES('tc dk c jn n t sr ge', 'a a kn bc n i af h');
INSERT INTO t2 VALUES('ie ii d i b sa qo rf', 'a h m aq i b m fn');
INSERT INTO t2 VALUES('gs r fo a er m h li', 'tm c p gl eb ml q r');
INSERT INTO t2 VALUES('k fe fd rd a gi ho kk', 'ng m c r d ml rm r');
}
faultsim_save_and_close
foreach {tn expr res} {
1 { dk } 7
2 { m f } 1
3 { f* } {10 9 8 6 5 4 3 1}
4 { m OR f } {10 9 8 5 4 1}
5 { sn + gh } {5}
6 { "sn gh" } {5}
7 { NEAR(r a, 5) } {9}
} {
do_faultsim_test 4.$tn -prep {
faultsim_restore_and_reopen
} -body "
execsql { SELECT rowid FROM t2 WHERE t2 MATCH '$expr' }
" -test "
faultsim_test_result {[list 0 $res]}
"
}
finish_test
+12 -2
View File
@@ -129,6 +129,8 @@ proc do_faultsim_test {name args} {
set DEFAULT(-test) ""
set DEFAULT(-install) ""
set DEFAULT(-uninstall) ""
set DEFAULT(-start) 1
set DEFAULT(-end) 0
fix_testname name
@@ -146,7 +148,8 @@ proc do_faultsim_test {name args} {
}
set testspec [list -prep $O(-prep) -body $O(-body) \
-test $O(-test) -install $O(-install) -uninstall $O(-uninstall)
-test $O(-test) -install $O(-install) -uninstall $O(-uninstall) \
-start $O(-start) -end $O(-end)
]
foreach f [lsort -unique $faultlist] {
eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
@@ -318,6 +321,8 @@ proc faultsim_test_result_int {args} {
#
# -test Script to execute after -body.
#
# -start Index of first fault to inject (default 1)
#
proc do_one_faultsim_test {testname args} {
set DEFAULT(-injectstart) "expr"
@@ -330,6 +335,8 @@ proc do_one_faultsim_test {testname args} {
set DEFAULT(-test) ""
set DEFAULT(-install) ""
set DEFAULT(-uninstall) ""
set DEFAULT(-start) 1
set DEFAULT(-end) 0
array set O [array get DEFAULT]
array set O $args
@@ -346,7 +353,10 @@ proc do_one_faultsim_test {testname args} {
eval $O(-install)
set stop 0
for {set iFail 1} {!$stop} {incr iFail} {
for {set iFail $O(-start)} \
{!$stop && ($O(-end)==0 || $iFail<=$O(-end))} \
{incr iFail} \
{
# Evaluate the -prep script.
#