The virtual table interface allows for a cursor to field multiple
xFilter() calls.  For instance, if a join is done with a virtual
table, there could be a call for each row which potentially matches.
Unfortunately, fulltextFilter() assumes that it has a fresh cursor,
and overwrites a prepared statement and a malloc'ed pointer, resulting
in unfinalized statements and a memory leak.

This change hacks the code to manually clean up offending items in
fulltextFilter(), emphasis on "hacks", since it's a fragile fix
insofar as future additions to fulltext_cursor could continue to have
the problem. (CVS 3521)

FossilOrigin-Name: 18142fdb6d1f5bfdbb1155274502b9a602885fcb
This commit is contained in:
shess 2006-11-29 05:17:28 +00:00
parent 7e3d0c2d2f
commit 5c327dbb46
4 changed files with 43 additions and 28 deletions

View File

@ -2040,6 +2040,7 @@ out:
/* Decide how to handle an SQL query. */
static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int i;
TRACE(("FTS1 BestIndex\n"));
for(i=0; i<pInfo->nConstraint; ++i){
const struct sqlite3_index_constraint *pConstraint;
@ -2048,10 +2049,12 @@ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( pConstraint->iColumn==-1 &&
pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
pInfo->idxNum = QUERY_ROWID; /* lookup by rowid */
TRACE(("FTS1 QUERY_ROWID\n"));
} else if( pConstraint->iColumn>=0 &&
pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
/* full-text search */
pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn;
TRACE(("FTS1 QUERY_FULLTEXT %d\n", pConstraint->iColumn));
} else continue;
pInfo->aConstraintUsage[i].argvIndex = 1;
@ -2066,7 +2069,6 @@ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
}
pInfo->idxNum = QUERY_GENERIC;
TRACE(("FTS1 BestIndex\n"));
return SQLITE_OK;
}
@ -2818,6 +2820,11 @@ static int fulltextQuery(
** number idxNum-QUERY_FULLTEXT, 0 indexed. argv[0] is the right-hand
** side of the MATCH operator.
*/
/* TODO(shess) Upgrade the cursor initialization and destruction to
** account for fulltextFilter() being called multiple times on the
** same cursor. The current solution is very fragile. Apply fix to
** fts2 as appropriate.
*/
static int fulltextFilter(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, const char *idxStr, /* Which indexing scheme to use */
@ -2832,9 +2839,10 @@ static int fulltextFilter(
zSql = sqlite3_mprintf("select rowid, * from %%_content %s",
idxNum==QUERY_GENERIC ? "" : "where rowid=?");
sqlite3_finalize(c->pStmt);
rc = sql_prepare(v->db, v->zName, &c->pStmt, zSql);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto out;
if( rc!=SQLITE_OK ) return rc;
c->iCursorType = idxNum;
switch( idxNum ){
@ -2843,7 +2851,7 @@ static int fulltextFilter(
case QUERY_ROWID:
rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0]));
if( rc!=SQLITE_OK ) goto out;
if( rc!=SQLITE_OK ) return rc;
break;
default: /* full-text search */
@ -2854,16 +2862,14 @@ static int fulltextFilter(
assert( argc==1 );
queryClear(&c->q);
rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &pResult, &c->q);
if( rc!=SQLITE_OK ) goto out;
if( rc!=SQLITE_OK ) return rc;
if( c->result.pDoclist!=NULL ) docListDelete(c->result.pDoclist);
readerInit(&c->result, pResult);
break;
}
}
rc = fulltextNext(pCursor);
out:
return rc;
return fulltextNext(pCursor);
}
/* This is the xEof method of the virtual table. The SQLite core

View File

@ -2613,6 +2613,7 @@ out:
/* Decide how to handle an SQL query. */
static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int i;
TRACE(("FTS2 BestIndex\n"));
for(i=0; i<pInfo->nConstraint; ++i){
const struct sqlite3_index_constraint *pConstraint;
@ -2621,10 +2622,12 @@ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
if( pConstraint->iColumn==-1 &&
pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
pInfo->idxNum = QUERY_ROWID; /* lookup by rowid */
TRACE(("FTS2 QUERY_ROWID\n"));
} else if( pConstraint->iColumn>=0 &&
pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
/* full-text search */
pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn;
TRACE(("FTS2 QUERY_FULLTEXT %d\n", pConstraint->iColumn));
} else continue;
pInfo->aConstraintUsage[i].argvIndex = 1;
@ -2639,7 +2642,6 @@ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
}
pInfo->idxNum = QUERY_GENERIC;
TRACE(("FTS2 BestIndex\n"));
return SQLITE_OK;
}
@ -3034,10 +3036,8 @@ static int fulltextClose(sqlite3_vtab_cursor *pCursor){
sqlite3_finalize(c->pStmt);
queryClear(&c->q);
snippetClear(&c->snippet);
if( c->result.nData!=0 ){
dlrDestroy(&c->reader);
dataBufferDestroy(&c->result);
}
if( c->result.nData!=0 ) dlrDestroy(&c->reader);
dataBufferDestroy(&c->result);
free(c);
return SQLITE_OK;
}
@ -3400,6 +3400,11 @@ static int fulltextQuery(
** number idxNum-QUERY_FULLTEXT, 0 indexed. argv[0] is the right-hand
** side of the MATCH operator.
*/
/* TODO(shess) Upgrade the cursor initialization and destruction to
** account for fulltextFilter() being called multiple times on the
** same cursor. The current solution is very fragile. Apply fix to
** fts2 as appropriate.
*/
static int fulltextFilter(
sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */
int idxNum, const char *idxStr, /* Which indexing scheme to use */
@ -3414,9 +3419,10 @@ static int fulltextFilter(
zSql = sqlite3_mprintf("select rowid, * from %%_content %s",
idxNum==QUERY_GENERIC ? "" : "where rowid=?");
sqlite3_finalize(c->pStmt);
rc = sql_prepare(v->db, v->zName, &c->pStmt, zSql);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ) goto out;
if( rc!=SQLITE_OK ) return rc;
c->iCursorType = idxNum;
switch( idxNum ){
@ -3425,7 +3431,7 @@ static int fulltextFilter(
case QUERY_ROWID:
rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0]));
if( rc!=SQLITE_OK ) goto out;
if( rc!=SQLITE_OK ) return rc;
break;
default: /* full-text search */
@ -3434,7 +3440,13 @@ static int fulltextFilter(
assert( idxNum<=QUERY_FULLTEXT+v->nColumn);
assert( argc==1 );
queryClear(&c->q);
dataBufferInit(&c->result, 0);
if( c->result.nData!=0 ){
/* This case happens if the same cursor is used repeatedly. */
dlrDestroy(&c->reader);
dataBufferReset(&c->result);
}else{
dataBufferInit(&c->result, 0);
}
rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q);
if( rc!=SQLITE_OK ) return rc;
if( c->result.nData!=0 ){
@ -3444,10 +3456,7 @@ static int fulltextFilter(
}
}
rc = fulltextNext(pCursor);
out:
return rc;
return fulltextNext(pCursor);
}
/* This is the xEof method of the virtual table. The SQLite core

View File

@ -1,5 +1,5 @@
C Delta-encode\sterms\sin\sinterior\snodes.\s\sWhile\sexperiments\shave\sshown\nthat\sthis\sis\sof\smarginal\sutility\swhen\sencoding\sterms\sresulting\sfrom\nregular\sEnglish\stext,\sit\sturns\sout\sto\sbe\svery\suseful\swhen\sencoding\ninputs\swith\svery\slarge\sterms.\s(CVS\s3520)
D 2006-11-29T01:02:03
C http://www.sqlite.org/cvstrac/tktview?tn=2046\n\nThe\svirtual\stable\sinterface\sallows\sfor\sa\scursor\sto\sfield\smultiple\nxFilter()\scalls.\s\sFor\sinstance,\sif\sa\sjoin\sis\sdone\swith\sa\svirtual\ntable,\sthere\scould\sbe\sa\scall\sfor\seach\srow\swhich\spotentially\smatches.\nUnfortunately,\sfulltextFilter()\sassumes\sthat\sit\shas\sa\sfresh\scursor,\nand\soverwrites\sa\sprepared\sstatement\sand\sa\smalloc'ed\spointer,\sresulting\nin\sunfinalized\sstatements\sand\sa\smemory\sleak.\n\nThis\schange\shacks\sthe\scode\sto\smanually\sclean\sup\soffending\sitems\sin\nfulltextFilter(),\semphasis\son\s"hacks",\ssince\sit's\sa\sfragile\sfix\ninsofar\sas\sfuture\sadditions\sto\sfulltext_cursor\scould\scontinue\sto\shave\nthe\sproblem.\s(CVS\s3521)
D 2006-11-29T05:17:28
F Makefile.in 8e14898d41a53033ecb687d93c9cd5d109fb9ae3
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@ -21,7 +21,7 @@ F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
F ext/fts1/ft_hash.h 1a35e654a235c2c662d3ca0dfc3138ad60b8b7d5
F ext/fts1/fts1.c 78218fb06050899508387de38ce2769f5e57ed8e
F ext/fts1/fts1.c a6b6a7b5ebc3f2fd8b1a8d65e8e7334c03b522d4
F ext/fts1/fts1.h 6060b8f62c1d925ea8356cb1a6598073eb9159a6
F ext/fts1/fts1_hash.c 3196cee866edbebb1c0521e21672e6d599965114
F ext/fts1/fts1_hash.h 957d378355ed29f672cd5add012ce8b088a5e089
@ -33,7 +33,7 @@ F ext/fts1/fulltext.h 08525a47852d1d62a0be81d3fc3fe2d23b094efd
F ext/fts1/simple_tokenizer.c 1844d72f7194c3fd3d7e4173053911bf0661b70d
F ext/fts1/tokenizer.h 0c53421b832366d20d720d21ea3e1f6e66a36ef9
F ext/fts2/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts2/fts2.c 6065a73ad89e7fb0dcfc41d1b110f856dea98dc8
F ext/fts2/fts2.c 94b438480762ba2a2cb5e5d66b80290e93c50960
F ext/fts2/fts2.h bbdab26d34f91974d5b9ade8b7836c140a7c4ce1
F ext/fts2/fts2_hash.c b3f22116d4ef0bc8f2da6e3fdc435c86d0951a9b
F ext/fts2/fts2_hash.h e283308156018329f042816eb09334df714e105e
@ -421,7 +421,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
P 272c1a6e61d053121b5412564948dad4366b5727
R 64f64a706f1c764008e348249e53ac19
P c8151a998ec2423b417566823dc9957c7d5d782c
R f017f7c21acd0dc81410dabbd79839d6
U shess
Z 613a143cab46a942074b48bd6bce5a4c
Z 7ba30b5c9f8e043c81e82dcfd18e4b5c

View File

@ -1 +1 @@
c8151a998ec2423b417566823dc9957c7d5d782c
18142fdb6d1f5bfdbb1155274502b9a602885fcb