From 5c327dbb4683645c47e334c7f4e7fa908f2e1184 Mon Sep 17 00:00:00 2001 From: shess Date: Wed, 29 Nov 2006 05:17:28 +0000 Subject: [PATCH] http://www.sqlite.org/cvstrac/tktview?tn=2046 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 --- ext/fts1/fts1.c | 22 ++++++++++++++-------- ext/fts2/fts2.c | 33 +++++++++++++++++++++------------ manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ext/fts1/fts1.c b/ext/fts1/fts1.c index 480fc4b9b0..e0e2560ee5 100644 --- a/ext/fts1/fts1.c +++ b/ext/fts1/fts1.c @@ -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; inConstraint; ++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 diff --git a/ext/fts2/fts2.c b/ext/fts2/fts2.c index 8e906f7db0..070089bdaa 100644 --- a/ext/fts2/fts2.c +++ b/ext/fts2/fts2.c @@ -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; inConstraint; ++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 diff --git a/manifest b/manifest index 4306c87da1..4c8bb77f96 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 33103b55f7..955563d166 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c8151a998ec2423b417566823dc9957c7d5d782c \ No newline at end of file +18142fdb6d1f5bfdbb1155274502b9a602885fcb \ No newline at end of file -- 2.47.2