Begin testing fts5 OOM and IO error handling.

FossilOrigin-Name: 2037dba62fdd995ad15b642abe499a790f5ffe5c
This commit is contained in:
dan 2014-12-03 17:27:35 +00:00
parent 615a9ae5db
commit 845d0ab323
11 changed files with 744 additions and 672 deletions

View File

@ -308,24 +308,19 @@ static int fts5InitVtab(
){
Fts5Global *pGlobal = (Fts5Global*)pAux;
const char **azConfig = (const char**)argv;
int rc; /* Return code */
int rc = SQLITE_OK; /* Return code */
Fts5Config *pConfig; /* Results of parsing argc/argv */
Fts5Table *pTab = 0; /* New virtual table object */
/* Parse the arguments */
rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
/* Allocate the new vtab object */
/* Allocate the new vtab object and parse the configuration */
pTab = (Fts5Table*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Table));
if( rc==SQLITE_OK ){
pTab = (Fts5Table*)sqlite3_malloc(sizeof(Fts5Table));
if( pTab==0 ){
rc = SQLITE_NOMEM;
}else{
memset(pTab, 0, sizeof(Fts5Table));
pTab->pConfig = pConfig;
pTab->pGlobal = pGlobal;
}
rc = sqlite3Fts5ConfigParse(pGlobal, db, argc, azConfig, &pConfig, pzErr);
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
}
if( rc==SQLITE_OK ){
pTab->pConfig = pConfig;
pTab->pGlobal = pGlobal;
}
/* Open the index sub-system */

View File

@ -187,6 +187,9 @@ int sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
);
/* Malloc utility */
void *sqlite3Fts5MallocZero(int *pRc, int nByte);
/*
** End of interface to code in fts5_buffer.c.
**************************************************************************/
@ -225,24 +228,25 @@ int sqlite3Fts5IndexClose(Fts5Index *p, int bDestroy);
** Open a new iterator to iterate though all docids that match the
** specified token or token prefix.
*/
Fts5IndexIter *sqlite3Fts5IndexQuery(
int sqlite3Fts5IndexQuery(
Fts5Index *p, /* FTS index to query */
const char *pToken, int nToken, /* Token (or prefix) to query for */
int flags /* Mask of FTS5INDEX_QUERY_X flags */
int flags, /* Mask of FTS5INDEX_QUERY_X flags */
Fts5IndexIter **ppIter
);
/*
** Docid list iteration.
*/
int sqlite3Fts5IterEof(Fts5IndexIter*);
void sqlite3Fts5IterNext(Fts5IndexIter*);
void sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
int sqlite3Fts5IterEof(Fts5IndexIter*);
int sqlite3Fts5IterNext(Fts5IndexIter*);
int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch);
i64 sqlite3Fts5IterRowid(Fts5IndexIter*);
/*
** Obtain the position list that corresponds to the current position.
*/
const u8 *sqlite3Fts5IterPoslist(Fts5IndexIter*, int *pn);
int sqlite3Fts5IterPoslist(Fts5IndexIter*, const u8 **pp, int *pn);
/*
** Close an iterator opened by sqlite3Fts5IndexQuery().
@ -259,7 +263,7 @@ void sqlite3Fts5IterClose(Fts5IndexIter*);
** unique token in the document with an iCol value less than zero. The iPos
** argument is ignored for a delete.
*/
void sqlite3Fts5IndexWrite(
int sqlite3Fts5IndexWrite(
Fts5Index *p, /* Index to write to */
int iCol, /* Column token appears in (-ve -> delete) */
int iPos, /* Position of token within column */
@ -270,7 +274,7 @@ void sqlite3Fts5IndexWrite(
** Indicate that subsequent calls to sqlite3Fts5IndexWrite() pertain to
** document iDocid.
*/
void sqlite3Fts5IndexBeginWrite(
int sqlite3Fts5IndexBeginWrite(
Fts5Index *p, /* Index to write to */
i64 iDocid /* Docid to add or remove data from */
);
@ -321,9 +325,6 @@ int sqlite3Fts5IndexSetCookie(Fts5Index*, int);
*/
int sqlite3Fts5IndexReads(Fts5Index *p);
/* Malloc utility */
void *sqlite3Fts5MallocZero(int *pRc, int nByte);
/*
** End of interface to code in fts5_index.c.
**************************************************************************/

View File

@ -282,4 +282,18 @@ void sqlite3Fts5BufferAppendListElem(
*pOut = '\0';
}
void *sqlite3Fts5MallocZero(int *pRc, int nByte){
void *pRet = 0;
if( *pRc==SQLITE_OK ){
pRet = sqlite3_malloc(nByte);
if( pRet==0 && nByte>0 ){
*pRc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
}
}
return pRet;
}

View File

@ -115,8 +115,13 @@ static int fts5ConfigParseSpecial(
**
** Return 0 if an OOM error is encountered.
*/
static char *fts5Strdup(const char *z){
return sqlite3_mprintf("%s", z);
static char *fts5Strdup(int *pRc, const char *z){
char *pRet = 0;
if( *pRc==SQLITE_OK ){
pRet = sqlite3_mprintf("%s", z);
if( pRet==0 ) *pRc = SQLITE_NOMEM;
}
return pRet;
}
/*
@ -159,44 +164,41 @@ int sqlite3Fts5ConfigParse(
pRet->db = db;
pRet->iCookie = -1;
pRet->azCol = (char**)sqlite3_malloc(sizeof(char*) * nArg);
pRet->zDb = fts5Strdup(azArg[1]);
pRet->zName = fts5Strdup(azArg[2]);
if( sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
*pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
rc = SQLITE_ERROR;
}else if( pRet->azCol==0 || pRet->zDb==0 || pRet->zName==0 ){
rc = SQLITE_NOMEM;
}else{
int i;
for(i=3; rc==SQLITE_OK && i<nArg; i++){
char *zDup = fts5Strdup(azArg[i]);
if( zDup==0 ){
rc = SQLITE_NOMEM;
}else{
/* Check if this is a special directive - "cmd=arg" */
if( zDup[0]!='"' && zDup[0]!='\'' && zDup[0]!='[' && zDup[0]!='`' ){
char *p = zDup;
while( *p && *p!='=' ) p++;
if( *p ){
char *zArg = &p[1];
*p = '\0';
sqlite3Fts5Dequote(zArg);
rc = fts5ConfigParseSpecial(pRet, zDup, zArg, pzErr);
sqlite3_free(zDup);
zDup = 0;
}
}
/* 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". */
pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
pRet->zDb = fts5Strdup(&rc, azArg[1]);
pRet->zName = fts5Strdup(&rc, azArg[2]);
if( rc==SQLITE_OK ){
if( sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
*pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
rc = SQLITE_ERROR;
}else{
int i;
for(i=3; rc==SQLITE_OK && i<nArg; i++){
char *zDup = fts5Strdup(&rc, azArg[i]);
if( zDup ){
sqlite3Fts5Dequote(zDup);
pRet->azCol[pRet->nCol++] = zDup;
if( sqlite3_stricmp(zDup, FTS5_RANK_NAME)==0 ){
*pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zDup);
rc = SQLITE_ERROR;
/* Check if this is a special directive - "cmd=arg" */
if( zDup[0]!='"' && zDup[0]!='\'' && zDup[0]!='[' && zDup[0]!='`' ){
char *p = zDup;
while( *p && *p!='=' ) p++;
if( *p ){
char *zArg = &p[1];
*p = '\0';
sqlite3Fts5Dequote(zArg);
rc = fts5ConfigParseSpecial(pRet, zDup, zArg, pzErr);
sqlite3_free(zDup);
zDup = 0;
}
}
/* 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". */
if( zDup ){
sqlite3Fts5Dequote(zDup);
pRet->azCol[pRet->nCol++] = zDup;
if( sqlite3_stricmp(zDup, FTS5_RANK_NAME)==0 ){
*pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zDup);
rc = SQLITE_ERROR;
}
}
}
}

View File

@ -386,8 +386,11 @@ static int fts5ExprPhraseIsMatch(
/* Initialize a term iterator for each term in the phrase */
for(i=0; i<pPhrase->nTerm; i++){
int n;
const u8 *a = sqlite3Fts5IterPoslist(pPhrase->aTerm[i].pIter, &n);
if( sqlite3Fts5PoslistReaderInit(iCol, a, n, &aIter[i]) ) goto ismatch_out;
const u8 *a;
rc = sqlite3Fts5IterPoslist(pPhrase->aTerm[i].pIter, &a, &n);
if( rc || sqlite3Fts5PoslistReaderInit(iCol, a, n, &aIter[i]) ){
goto ismatch_out;
}
}
while( 1 ){
@ -576,22 +579,21 @@ static int fts5ExprNearAdvanceAll(
Fts5ExprNearset *pNear, /* Near object to advance iterators of */
int *pbEof /* OUT: Set to true if phrase at EOF */
){
int rc = SQLITE_OK; /* Return code */
int i, j; /* Phrase and token index, respectively */
for(i=0; i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
for(j=0; j<pPhrase->nTerm; j++){
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
sqlite3Fts5IterNext(pIter);
if( sqlite3Fts5IterEof(pIter) ){
int rc = sqlite3Fts5IterNext(pIter);
if( rc || sqlite3Fts5IterEof(pIter) ){
*pbEof = 1;
return rc;
}
}
}
return rc;
return SQLITE_OK;
}
/*
@ -711,21 +713,21 @@ static int fts5ExprNearNextMatch(
rc = fts5ExprNearNextRowidMatch(pExpr, pNode, bFromValid, iFrom);
if( pNode->bEof || rc!=SQLITE_OK ) break;
for(i=0; i<pNear->nPhrase; i++){
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
if( pPhrase->nTerm>1 || pNear->iCol>=0 ){
int bMatch = 0;
rc = fts5ExprPhraseIsMatch(pExpr, pNear->iCol, pPhrase, &bMatch);
if( rc!=SQLITE_OK ) return rc;
if( bMatch==0 ) break;
}else{
int n;
const u8 *a = sqlite3Fts5IterPoslist(pPhrase->aTerm[0].pIter, &n);
const u8 *a;
rc = sqlite3Fts5IterPoslist(pPhrase->aTerm[0].pIter, &a, &n);
fts5BufferSet(&rc, &pPhrase->poslist, n, a);
}
}
if( i==pNear->nPhrase ){
if( rc==SQLITE_OK && i==pNear->nPhrase ){
int bMatch = 1;
if( pNear->nPhrase>1 ){
rc = fts5ExprNearIsMatch(pNear, &bMatch);
@ -735,7 +737,9 @@ static int fts5ExprNearNextMatch(
/* If control flows to here, then the current rowid is not a match.
** Advance all term iterators in all phrases to the next rowid. */
rc = fts5ExprNearAdvanceAll(pExpr, pNear, &pNode->bEof);
if( rc==SQLITE_OK ){
rc = fts5ExprNearAdvanceAll(pExpr, pNear, &pNode->bEof);
}
if( pNode->bEof || rc!=SQLITE_OK ) break;
}
@ -755,24 +759,26 @@ static int fts5ExprNearInitAll(
Fts5ExprTerm *pTerm;
Fts5ExprPhrase *pPhrase;
int i, j;
int rc = SQLITE_OK;
for(i=0; i<pNear->nPhrase; i++){
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
pPhrase = pNear->apPhrase[i];
for(j=0; j<pPhrase->nTerm; j++){
pTerm = &pPhrase->aTerm[j];
pTerm->pIter = sqlite3Fts5IndexQuery(
rc = sqlite3Fts5IndexQuery(
pExpr->pIndex, pTerm->zTerm, strlen(pTerm->zTerm),
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bAsc ? FTS5INDEX_QUERY_ASC : 0)
(pExpr->bAsc ? FTS5INDEX_QUERY_ASC : 0),
&pTerm->pIter
);
if( pTerm->pIter && sqlite3Fts5IterEof(pTerm->pIter) ){
pNode->bEof = 1;
return SQLITE_OK;
break;
}
}
}
return SQLITE_OK;
return rc;
}
/* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */

File diff suppressed because it is too large Load Diff

View File

@ -226,21 +226,23 @@ int sqlite3Fts5StorageOpen(
*/
int sqlite3Fts5StorageClose(Fts5Storage *p, int bDestroy){
int rc = SQLITE_OK;
int i;
if( p ){
int i;
/* Finalize all SQL statements */
for(i=0; i<ArraySize(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
/* Finalize all SQL statements */
for(i=0; i<ArraySize(p->aStmt); i++){
sqlite3_finalize(p->aStmt[i]);
}
/* If required, remove the shadow tables from the database */
if( bDestroy ){
rc = sqlite3Fts5DropTable(p->pConfig, "content");
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "docsize");
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "config");
}
sqlite3_free(p);
}
/* If required, remove the shadow tables from the database */
if( bDestroy ){
rc = sqlite3Fts5DropTable(p->pConfig, "content");
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "docsize");
if( rc==SQLITE_OK ) rc = sqlite3Fts5DropTable(p->pConfig, "config");
}
sqlite3_free(p);
return rc;
}
@ -265,8 +267,7 @@ static int fts5StorageInsertCallback(
Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
Fts5Index *pIdx = pCtx->pStorage->pIndex;
pCtx->szCol = iPos+1;
sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, iPos, pToken, nToken);
return SQLITE_OK;
return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, iPos, pToken, nToken);
}
/*
@ -288,8 +289,8 @@ static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
Fts5InsertCtx ctx;
ctx.pStorage = p;
ctx.iCol = -1;
sqlite3Fts5IndexBeginWrite(p->pIndex, iDel);
for(iCol=1; iCol<=pConfig->nCol; iCol++){
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, iDel);
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
rc = sqlite3Fts5Tokenize(pConfig,
(const char*)sqlite3_column_text(pSeek, iCol),
sqlite3_column_bytes(pSeek, iCol),
@ -475,8 +476,10 @@ int sqlite3Fts5StorageInsert(
*piRowid = sqlite3_last_insert_rowid(pConfig->db);
/* Add new entries to the FTS index */
sqlite3Fts5IndexBeginWrite(p->pIndex, *piRowid);
ctx.pStorage = p;
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexBeginWrite(p->pIndex, *piRowid);
ctx.pStorage = p;
}
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
ctx.szCol = 0;
rc = sqlite3Fts5Tokenize(pConfig,

View File

@ -1,5 +1,5 @@
C Add\sa\sconfiguration\soption\sto\sremap\sthe\s"rank"\scolumn\sto\san\sauxiliary\sfts5\sfunction.
D 2014-12-02T20:18:11.604
C Begin\stesting\sfts5\sOOM\sand\sIO\serror\shandling.
D 2014-12-03T17:27:35.105
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -104,16 +104,16 @@ 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 572bd5d4d272ca562240dc1905538f060783ab78
F ext/fts5/fts5.c 1dae34f4a788b5760c52b914d6384d83ee027b35
F ext/fts5/fts5.h 72fc1e9995b1ddc254a487b9528614a83bd3dfb6
F ext/fts5/fts5Int.h 9dbf415de032b1cc770dcedaa5a8e434d88ca90c
F ext/fts5/fts5Int.h 36054b1dfc4881a9b94f945b348ab6cc01c0c7a5
F ext/fts5/fts5_aux.c 0e3e5fea6bf5772805afe14c95cb5f16e03e4b3f
F ext/fts5/fts5_buffer.c c79d67a5a611521f1f3b9d495981f22c02ef4bdb
F ext/fts5/fts5_config.c 664fdc8519b55753f5c24d7b45176f05586b7965
F ext/fts5/fts5_expr.c d317be07d70223a6865444f17982570260b690a5
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_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
F ext/fts5/fts5_index.c 7e7023f3a29f104b44df2ca2474b296b8dfe447c
F ext/fts5/fts5_storage.c 0198c5976cefa5e8d3f1cfffa3587d0dd594fb2a
F ext/fts5/fts5_index.c 9233b8b1f519e50d9ec139031032d9211dfcb541
F ext/fts5/fts5_storage.c bfeedb83b095a1018f4f531c3cc3f9099e9f9081
F ext/fts5/fts5_tcl.c 5272224faf9be129679da5e19d788f0307afc375
F ext/fts5/fts5_tokenize.c 8360c0d1ae0d4696f3cc13f7c67a2db6011cdc5b
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
@ -612,6 +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/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@ -778,7 +779,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
F test/permutations.test 4f71bc5c9ce9a249cc94ad415cda809ce7f2360b
F test/permutations.test a762abd3f97809c877c93e6b526ec07bb2a75b96
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@ -1207,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 9c1697a2aa1f601e6eb11704abe63a73c8105447
R 30808e5592c3e61509564bec30e4914f
P b5f5971283b9b2f60c16f9675099855af95012cd
R cb30a6b5c5f7ea511cc1ede93a5d038a
U dan
Z 9589e0356694de369bd9f49ee042fc35
Z f7fa77a51653f0fa8e3497900e76f571

View File

@ -1 +1 @@
b5f5971283b9b2f60c16f9675099855af95012cd
2037dba62fdd995ad15b642abe499a790f5ffe5c

37
test/fts5fault1.test Normal file
View File

@ -0,0 +1,37 @@
# 2014 June 17
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
# This file implements regression tests for SQLite library. The
# focus of this script is testing the FTS5 module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix fts5fault1
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
faultsim_save_and_close
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE VIRTUAL TABLE t1 USING fts5(a) }
} -test {
faultsim_test_result {0 {}}
}
finish_test

View File

@ -225,8 +225,12 @@ test_suite "fts3" -prefix "" -description {
test_suite "fts5" -prefix "" -description {
All FTS5 tests.
} -files {
fts5aa.test fts5ab.test fts5ac.test fts5ad.test fts5ae.test fts5ea.test
fts5aa.test fts5ab.test fts5ac.test fts5ad.test fts5ae.test
fts5af.test fts5ag.test fts5ah.test fts5ai.test fts5aj.test
fts5ak.test fts5al.test
fts5ea.test
fts5fault1.test
}
test_suite "nofaultsim" -prefix "" -description {