Update the spellfix virtual table extension so that an explicit "top = ?" constraint works even if there is also a "distance < ?" or "distance <= ?" constraint.
FossilOrigin-Name: 0888838371608558f31d5bcb5fed1c8861aa52c1
This commit is contained in:
parent
dca929040a
commit
b20a42e316
@ -1770,6 +1770,7 @@ struct spellfix1_cursor {
|
|||||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||||
spellfix1_vtab *pVTab; /* The table to which this cursor belongs */
|
spellfix1_vtab *pVTab; /* The table to which this cursor belongs */
|
||||||
char *zPattern; /* rhs of MATCH clause */
|
char *zPattern; /* rhs of MATCH clause */
|
||||||
|
int idxNum; /* idxNum value passed to xFilter() */
|
||||||
int nRow; /* Number of rows of content */
|
int nRow; /* Number of rows of content */
|
||||||
int nAlloc; /* Number of allocated rows */
|
int nAlloc; /* Number of allocated rows */
|
||||||
int iRow; /* Current row of content */
|
int iRow; /* Current row of content */
|
||||||
@ -2040,26 +2041,19 @@ static int spellfix1Close(sqlite3_vtab_cursor *cur){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SPELLFIX_IDXNUM_MATCH 0x01 /* word MATCH $str */
|
||||||
|
#define SPELLFIX_IDXNUM_LANGID 0x02 /* langid == $langid */
|
||||||
|
#define SPELLFIX_IDXNUM_TOP 0x04 /* top = $top */
|
||||||
|
#define SPELLFIX_IDXNUM_SCOPE 0x08 /* scope = $scope */
|
||||||
|
#define SPELLFIX_IDXNUM_DISTLT 0x10 /* distance < $distance */
|
||||||
|
#define SPELLFIX_IDXNUM_DISTLE 0x20 /* distance <= $distance */
|
||||||
|
#define SPELLFIX_IDXNUM_ROWID 0x40 /* rowid = $rowid */
|
||||||
|
#define SPELLFIX_IDXNUM_DIST (0x10|0x20) /* DISTLT and DISTLE */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Search for terms of these forms:
|
|
||||||
**
|
**
|
||||||
** (A) word MATCH $str
|
** The plan number is a bitmask of the SPELLFIX_IDXNUM_* values defined
|
||||||
** (B) langid == $langid
|
** above.
|
||||||
** (C) top = $top
|
|
||||||
** (D) scope = $scope
|
|
||||||
** (E) distance < $distance
|
|
||||||
** (F) distance <= $distance
|
|
||||||
** (G) rowid = $rowid
|
|
||||||
**
|
|
||||||
** The plan number is a bit mask formed with these bits:
|
|
||||||
**
|
|
||||||
** 0x01 (A) is found
|
|
||||||
** 0x02 (B) is found
|
|
||||||
** 0x04 (C) is found
|
|
||||||
** 0x08 (D) is found
|
|
||||||
** 0x10 (E) is found
|
|
||||||
** 0x20 (F) is found
|
|
||||||
** 0x40 (G) is found
|
|
||||||
**
|
**
|
||||||
** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid
|
** filter.argv[*] values contains $str, $langid, $top, $scope and $rowid
|
||||||
** if specified and in that order.
|
** if specified and in that order.
|
||||||
@ -2078,62 +2072,66 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|||||||
if( pConstraint->usable==0 ) continue;
|
if( pConstraint->usable==0 ) continue;
|
||||||
|
|
||||||
/* Terms of the form: word MATCH $str */
|
/* Terms of the form: word MATCH $str */
|
||||||
if( (iPlan & 1)==0
|
if( (iPlan & SPELLFIX_IDXNUM_MATCH)==0
|
||||||
&& pConstraint->iColumn==SPELLFIX_COL_WORD
|
&& pConstraint->iColumn==SPELLFIX_COL_WORD
|
||||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
||||||
){
|
){
|
||||||
iPlan |= 1;
|
iPlan |= SPELLFIX_IDXNUM_MATCH;
|
||||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terms of the form: langid = $langid */
|
/* Terms of the form: langid = $langid */
|
||||||
if( (iPlan & 2)==0
|
if( (iPlan & SPELLFIX_IDXNUM_LANGID)==0
|
||||||
&& pConstraint->iColumn==SPELLFIX_COL_LANGID
|
&& pConstraint->iColumn==SPELLFIX_COL_LANGID
|
||||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||||
){
|
){
|
||||||
iPlan |= 2;
|
iPlan |= SPELLFIX_IDXNUM_LANGID;
|
||||||
iLangTerm = i;
|
iLangTerm = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terms of the form: top = $top */
|
/* Terms of the form: top = $top */
|
||||||
if( (iPlan & 4)==0
|
if( (iPlan & SPELLFIX_IDXNUM_TOP)==0
|
||||||
&& pConstraint->iColumn==SPELLFIX_COL_TOP
|
&& pConstraint->iColumn==SPELLFIX_COL_TOP
|
||||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||||
){
|
){
|
||||||
iPlan |= 4;
|
iPlan |= SPELLFIX_IDXNUM_TOP;
|
||||||
iTopTerm = i;
|
iTopTerm = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terms of the form: scope = $scope */
|
/* Terms of the form: scope = $scope */
|
||||||
if( (iPlan & 8)==0
|
if( (iPlan & SPELLFIX_IDXNUM_SCOPE)==0
|
||||||
&& pConstraint->iColumn==SPELLFIX_COL_SCOPE
|
&& pConstraint->iColumn==SPELLFIX_COL_SCOPE
|
||||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||||
){
|
){
|
||||||
iPlan |= 8;
|
iPlan |= SPELLFIX_IDXNUM_SCOPE;
|
||||||
iScopeTerm = i;
|
iScopeTerm = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terms of the form: distance < $dist or distance <= $dist */
|
/* Terms of the form: distance < $dist or distance <= $dist */
|
||||||
if( (iPlan & (16|32))==0
|
if( (iPlan & SPELLFIX_IDXNUM_DIST)==0
|
||||||
&& pConstraint->iColumn==SPELLFIX_COL_DISTANCE
|
&& pConstraint->iColumn==SPELLFIX_COL_DISTANCE
|
||||||
&& (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
|
&& (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
|
||||||
|| pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
|
|| pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
|
||||||
){
|
){
|
||||||
iPlan |= pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ? 16 : 32;
|
if( pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT ){
|
||||||
|
iPlan |= SPELLFIX_IDXNUM_DISTLT;
|
||||||
|
}else{
|
||||||
|
iPlan |= SPELLFIX_IDXNUM_DISTLE;
|
||||||
|
}
|
||||||
iDistTerm = i;
|
iDistTerm = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Terms of the form: distance < $dist or distance <= $dist */
|
/* Terms of the form: distance < $dist or distance <= $dist */
|
||||||
if( (iPlan & 64)==0
|
if( (iPlan & SPELLFIX_IDXNUM_ROWID)==0
|
||||||
&& pConstraint->iColumn<0
|
&& pConstraint->iColumn<0
|
||||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
|
||||||
){
|
){
|
||||||
iPlan |= 64;
|
iPlan |= SPELLFIX_IDXNUM_ROWID;
|
||||||
iRowidTerm = i;
|
iRowidTerm = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( iPlan&1 ){
|
if( iPlan&SPELLFIX_IDXNUM_MATCH ){
|
||||||
int idx = 2;
|
int idx = 2;
|
||||||
pIdxInfo->idxNum = iPlan;
|
pIdxInfo->idxNum = iPlan;
|
||||||
if( pIdxInfo->nOrderBy==1
|
if( pIdxInfo->nOrderBy==1
|
||||||
@ -2142,25 +2140,25 @@ static int spellfix1BestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|||||||
){
|
){
|
||||||
pIdxInfo->orderByConsumed = 1; /* Default order by iScore */
|
pIdxInfo->orderByConsumed = 1; /* Default order by iScore */
|
||||||
}
|
}
|
||||||
if( iPlan&2 ){
|
if( iPlan&SPELLFIX_IDXNUM_LANGID ){
|
||||||
pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++;
|
pIdxInfo->aConstraintUsage[iLangTerm].argvIndex = idx++;
|
||||||
pIdxInfo->aConstraintUsage[iLangTerm].omit = 1;
|
pIdxInfo->aConstraintUsage[iLangTerm].omit = 1;
|
||||||
}
|
}
|
||||||
if( iPlan&4 ){
|
if( iPlan&SPELLFIX_IDXNUM_TOP ){
|
||||||
pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++;
|
pIdxInfo->aConstraintUsage[iTopTerm].argvIndex = idx++;
|
||||||
pIdxInfo->aConstraintUsage[iTopTerm].omit = 1;
|
pIdxInfo->aConstraintUsage[iTopTerm].omit = 1;
|
||||||
}
|
}
|
||||||
if( iPlan&8 ){
|
if( iPlan&SPELLFIX_IDXNUM_SCOPE ){
|
||||||
pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++;
|
pIdxInfo->aConstraintUsage[iScopeTerm].argvIndex = idx++;
|
||||||
pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1;
|
pIdxInfo->aConstraintUsage[iScopeTerm].omit = 1;
|
||||||
}
|
}
|
||||||
if( iPlan&(16|32) ){
|
if( iPlan&SPELLFIX_IDXNUM_DIST ){
|
||||||
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++;
|
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = idx++;
|
||||||
pIdxInfo->aConstraintUsage[iDistTerm].omit = 1;
|
pIdxInfo->aConstraintUsage[iDistTerm].omit = 1;
|
||||||
}
|
}
|
||||||
pIdxInfo->estimatedCost = 1e5;
|
pIdxInfo->estimatedCost = 1e5;
|
||||||
}else if( (iPlan & 64) ){
|
}else if( (iPlan & SPELLFIX_IDXNUM_ROWID) ){
|
||||||
pIdxInfo->idxNum = 64;
|
pIdxInfo->idxNum = SPELLFIX_IDXNUM_ROWID;
|
||||||
pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
|
pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1;
|
||||||
pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
|
pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1;
|
||||||
pIdxInfo->estimatedCost = 5;
|
pIdxInfo->estimatedCost = 5;
|
||||||
@ -2311,15 +2309,24 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pCur->nSearch++;
|
pCur->nSearch++;
|
||||||
iScore = spellfix1Score(iDist,iRank);
|
|
||||||
|
/* If there is a "distance < $dist" or "distance <= $dist" constraint,
|
||||||
|
** check if this row meets it. If not, jump back up to the top of the
|
||||||
|
** loop to process the next row. Otherwise, if the row does match the
|
||||||
|
** distance constraint, check if the pCur->a[] array is already full.
|
||||||
|
** If it is and no explicit "top = ?" constraint was present in the
|
||||||
|
** query, grow the array to ensure there is room for the new entry. */
|
||||||
|
assert( (p->iMaxDist>=0)==((pCur->idxNum & SPELLFIX_IDXNUM_DIST) ? 1 : 0) );
|
||||||
if( p->iMaxDist>=0 ){
|
if( p->iMaxDist>=0 ){
|
||||||
if( iDist>p->iMaxDist ) continue;
|
if( iDist>p->iMaxDist ) continue;
|
||||||
if( pCur->nRow>=pCur->nAlloc-1 ){
|
if( pCur->nRow>=pCur->nAlloc && (pCur->idxNum & SPELLFIX_IDXNUM_TOP)==0 ){
|
||||||
spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10);
|
spellfix1ResizeCursor(pCur, pCur->nAlloc*2 + 10);
|
||||||
if( pCur->a==0 ) break;
|
if( pCur->a==0 ) break;
|
||||||
}
|
}
|
||||||
idx = pCur->nRow;
|
}
|
||||||
}else if( pCur->nRow<pCur->nAlloc ){
|
|
||||||
|
iScore = spellfix1Score(iDist,iRank);
|
||||||
|
if( pCur->nRow<pCur->nAlloc ){
|
||||||
idx = pCur->nRow;
|
idx = pCur->nRow;
|
||||||
}else if( iScore<iWorst ){
|
}else if( iScore<iWorst ){
|
||||||
idx = idxWorst;
|
idx = idxWorst;
|
||||||
@ -2327,6 +2334,7 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
|
|||||||
}else{
|
}else{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
|
pCur->a[idx].zWord = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1));
|
||||||
if( pCur->a[idx].zWord==0 ){
|
if( pCur->a[idx].zWord==0 ){
|
||||||
p->rc = SQLITE_NOMEM;
|
p->rc = SQLITE_NOMEM;
|
||||||
@ -2361,10 +2369,10 @@ static void spellfix1RunQuery(MatchQuery *p, const char *zQuery, int nQuery){
|
|||||||
*/
|
*/
|
||||||
static int spellfix1FilterForMatch(
|
static int spellfix1FilterForMatch(
|
||||||
spellfix1_cursor *pCur,
|
spellfix1_cursor *pCur,
|
||||||
int idxNum,
|
|
||||||
int argc,
|
int argc,
|
||||||
sqlite3_value **argv
|
sqlite3_value **argv
|
||||||
){
|
){
|
||||||
|
int idxNum = pCur->idxNum;
|
||||||
const unsigned char *zMatchThis; /* RHS of the MATCH operator */
|
const unsigned char *zMatchThis; /* RHS of the MATCH operator */
|
||||||
EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */
|
EditDist3FromString *pMatchStr3 = 0; /* zMatchThis as an editdist string */
|
||||||
char *zPattern; /* Transliteration of zMatchThis */
|
char *zPattern; /* Transliteration of zMatchThis */
|
||||||
@ -2476,11 +2484,11 @@ filter_exit:
|
|||||||
*/
|
*/
|
||||||
static int spellfix1FilterForFullScan(
|
static int spellfix1FilterForFullScan(
|
||||||
spellfix1_cursor *pCur,
|
spellfix1_cursor *pCur,
|
||||||
int idxNum,
|
|
||||||
int argc,
|
int argc,
|
||||||
sqlite3_value **argv
|
sqlite3_value **argv
|
||||||
){
|
){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
int idxNum = pCur->idxNum;
|
||||||
char *zSql;
|
char *zSql;
|
||||||
spellfix1_vtab *pVTab = pCur->pVTab;
|
spellfix1_vtab *pVTab = pCur->pVTab;
|
||||||
spellfix1ResetCursor(pCur);
|
spellfix1ResetCursor(pCur);
|
||||||
@ -2521,10 +2529,11 @@ static int spellfix1Filter(
|
|||||||
){
|
){
|
||||||
spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
|
spellfix1_cursor *pCur = (spellfix1_cursor *)cur;
|
||||||
int rc;
|
int rc;
|
||||||
|
pCur->idxNum = idxNum;
|
||||||
if( idxNum & 1 ){
|
if( idxNum & 1 ){
|
||||||
rc = spellfix1FilterForMatch(pCur, idxNum, argc, argv);
|
rc = spellfix1FilterForMatch(pCur, argc, argv);
|
||||||
}else{
|
}else{
|
||||||
rc = spellfix1FilterForFullScan(pCur, idxNum, argc, argv);
|
rc = spellfix1FilterForFullScan(pCur, argc, argv);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\ssome\sproblems\sin\stest\scode\sdetected\sby\scppcheck.
|
C Update\sthe\sspellfix\svirtual\stable\sextension\sso\sthat\san\sexplicit\s"top\s=\s?"\sconstraint\sworks\seven\sif\sthere\sis\salso\sa\s"distance\s<\s?"\sor\s"distance\s<=\s?"\sconstraint.
|
||||||
D 2015-08-05T08:01:46.351
|
D 2015-08-05T15:29:32.743
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380
|
F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@ -196,7 +196,7 @@ F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
|||||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||||
F ext/misc/spellfix.c de9181ec188294dd2a1087b329ca55cfaa76a29d
|
F ext/misc/spellfix.c 86998fb73aefb7b5dc346ba8a58912f312da4996
|
||||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||||
@ -1369,7 +1369,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P dffd358f6cbf575d3b1045b1ce53429d15bade2a
|
P c9ff4ca4a0b44bbb8d6676144ddf77b04426e619
|
||||||
R 03d664fe9a880098c608c861d0111d6e
|
R 180a25ce6d192ff71ad9fad98491dc51
|
||||||
U dan
|
U dan
|
||||||
Z d772c3ac7a9d41bdcded0f7d87a12476
|
Z 9568c0ed64c13f8590f8982853b1718d
|
||||||
|
@ -1 +1 @@
|
|||||||
c9ff4ca4a0b44bbb8d6676144ddf77b04426e619
|
0888838371608558f31d5bcb5fed1c8861aa52c1
|
Loading…
Reference in New Issue
Block a user