mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Add the auxiliary highlight() function to fts5.
FossilOrigin-Name: 059092379f981eb919b500ce447006f9e645fc5a
This commit is contained in:
131
ext/fts5/fts5.c
131
ext/fts5/fts5.c
@@ -165,6 +165,9 @@ struct Fts5Cursor {
|
|||||||
Fts5Auxiliary *pAux; /* Currently executing extension function */
|
Fts5Auxiliary *pAux; /* Currently executing extension function */
|
||||||
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
|
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
|
||||||
int *aColumnSize; /* Values for xColumnSize() */
|
int *aColumnSize; /* Values for xColumnSize() */
|
||||||
|
|
||||||
|
int nInstCount; /* Number of phrase instances */
|
||||||
|
int *aInst; /* 3 integers per phrase instance */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -488,6 +491,18 @@ static int fts5StmtType(int idxNum){
|
|||||||
return FTS5_STMT_LOOKUP;
|
return FTS5_STMT_LOOKUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is called after the cursor passed as the only argument
|
||||||
|
** is moved to point at a different row. It clears all cached data
|
||||||
|
** specific to the previous row stored by the cursor object.
|
||||||
|
*/
|
||||||
|
static void fts5CsrNewrow(Fts5Cursor *pCsr){
|
||||||
|
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE );
|
||||||
|
sqlite3_free(pCsr->aInst);
|
||||||
|
pCsr->aInst = 0;
|
||||||
|
pCsr->nInstCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Close the cursor. For additional information see the documentation
|
** Close the cursor. For additional information see the documentation
|
||||||
** on the xClose method of the virtual table interface.
|
** on the xClose method of the virtual table interface.
|
||||||
@@ -499,6 +514,7 @@ static int fts5CloseMethod(sqlite3_vtab_cursor *pCursor){
|
|||||||
Fts5Auxdata *pData;
|
Fts5Auxdata *pData;
|
||||||
Fts5Auxdata *pNext;
|
Fts5Auxdata *pNext;
|
||||||
|
|
||||||
|
fts5CsrNewrow(pCsr);
|
||||||
if( pCsr->pStmt ){
|
if( pCsr->pStmt ){
|
||||||
int eStmt = fts5StmtType(pCsr->idxNum);
|
int eStmt = fts5StmtType(pCsr->idxNum);
|
||||||
sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
|
sqlite3Fts5StorageStmtRelease(pTab->pStorage, eStmt, pCsr->pStmt);
|
||||||
@@ -557,7 +573,7 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
|
|||||||
pSorter->aIdx[i] = &aBlob[nBlob] - a;
|
pSorter->aIdx[i] = &aBlob[nBlob] - a;
|
||||||
|
|
||||||
pSorter->aPoslist = a;
|
pSorter->aPoslist = a;
|
||||||
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE );
|
fts5CsrNewrow(pCsr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@@ -583,7 +599,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
|||||||
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
||||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||||
}
|
}
|
||||||
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE );
|
fts5CsrNewrow(pCsr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTS5_PLAN_SPECIAL: {
|
case FTS5_PLAN_SPECIAL: {
|
||||||
@@ -666,7 +682,7 @@ static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bAsc){
|
|||||||
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
if( sqlite3Fts5ExprEof(pCsr->pExpr) ){
|
||||||
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
CsrFlagSet(pCsr, FTS5CSR_EOF);
|
||||||
}
|
}
|
||||||
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_CONTENT | FTS5CSR_REQUIRE_DOCSIZE );
|
fts5CsrNewrow(pCsr);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1044,6 +1060,104 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
|
|||||||
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
|
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int fts5CsrPoslist(Fts5Cursor *pCsr, int iPhrase, const u8 **pa){
|
||||||
|
int n;
|
||||||
|
if( pCsr->pSorter ){
|
||||||
|
Fts5Sorter *pSorter = pCsr->pSorter;
|
||||||
|
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
|
||||||
|
n = pSorter->aIdx[iPhrase] - i1;
|
||||||
|
*pa = &pSorter->aPoslist[i1];
|
||||||
|
}else{
|
||||||
|
n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Ensure that the Fts5Cursor.nInstCount and aInst[] variables are populated
|
||||||
|
** correctly for the current view. Return SQLITE_OK if successful, or an
|
||||||
|
** SQLite error code otherwise.
|
||||||
|
*/
|
||||||
|
static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
if( pCsr->aInst==0 ){
|
||||||
|
Fts5PoslistReader *aIter; /* One iterator for each phrase */
|
||||||
|
int nIter; /* Number of iterators/phrases */
|
||||||
|
int nByte;
|
||||||
|
|
||||||
|
nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
||||||
|
nByte = sizeof(Fts5PoslistReader) * nIter;
|
||||||
|
aIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||||
|
if( aIter ){
|
||||||
|
Fts5Buffer buf = {0, 0, 0}; /* Build up aInst[] here */
|
||||||
|
int nInst; /* Number instances seen so far */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Initialize all iterators */
|
||||||
|
for(i=0; i<nIter; i++){
|
||||||
|
const u8 *a;
|
||||||
|
int n = fts5CsrPoslist(pCsr, i, &a);
|
||||||
|
sqlite3Fts5PoslistReaderInit(-1, a, n, &aIter[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while( 1 ){
|
||||||
|
int *aInst;
|
||||||
|
int iBest = -1;
|
||||||
|
for(i=0; i<nIter; i++){
|
||||||
|
if( aIter[i].bEof==0 && (iBest<0 || aIter[i].iPos<iBest) ){
|
||||||
|
iBest = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( iBest<0 ) break;
|
||||||
|
nInst++;
|
||||||
|
if( sqlite3Fts5BufferGrow(&rc, &buf, nInst * sizeof(int) * 3) ) break;
|
||||||
|
|
||||||
|
aInst = &((int*)buf.p)[3 * (nInst-1)];
|
||||||
|
aInst[0] = iBest;
|
||||||
|
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
|
||||||
|
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
|
||||||
|
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pCsr->aInst = (int*)buf.p;
|
||||||
|
pCsr->nInstCount = nInst;
|
||||||
|
sqlite3_free(aIter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
|
||||||
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||||
|
int rc;
|
||||||
|
if( SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
|
||||||
|
*pnInst = pCsr->nInstCount;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fts5ApiInst(
|
||||||
|
Fts5Context *pCtx,
|
||||||
|
int iIdx,
|
||||||
|
int *piPhrase,
|
||||||
|
int *piCol,
|
||||||
|
int *piOff
|
||||||
|
){
|
||||||
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||||
|
int rc;
|
||||||
|
if( SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
|
||||||
|
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
|
||||||
|
rc = SQLITE_RANGE;
|
||||||
|
}else{
|
||||||
|
*piPhrase = pCsr->aInst[iIdx*3];
|
||||||
|
*piCol = pCsr->aInst[iIdx*3 + 1];
|
||||||
|
*piOff = pCsr->aInst[iIdx*3 + 2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
|
static sqlite3_int64 fts5ApiRowid(Fts5Context *pCtx){
|
||||||
return fts5CursorRowid((Fts5Cursor*)pCtx);
|
return fts5CursorRowid((Fts5Cursor*)pCtx);
|
||||||
}
|
}
|
||||||
@@ -1088,14 +1202,7 @@ static int fts5ApiPoslist(
|
|||||||
){
|
){
|
||||||
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
||||||
const u8 *a; int n; /* Poslist for phrase iPhrase */
|
const u8 *a; int n; /* Poslist for phrase iPhrase */
|
||||||
if( pCsr->pSorter ){
|
n = fts5CsrPoslist(pCsr, iPhrase, &a);
|
||||||
Fts5Sorter *pSorter = pCsr->pSorter;
|
|
||||||
int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
|
|
||||||
n = pSorter->aIdx[iPhrase] - i1;
|
|
||||||
a = &pSorter->aPoslist[i1];
|
|
||||||
}else{
|
|
||||||
n = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, &a);
|
|
||||||
}
|
|
||||||
return sqlite3Fts5PoslistNext64(a, n, pi, piPos);
|
return sqlite3Fts5PoslistNext64(a, n, pi, piPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,6 +1269,8 @@ static const Fts5ExtensionApi sFts5Api = {
|
|||||||
fts5ApiTokenize,
|
fts5ApiTokenize,
|
||||||
fts5ApiPhraseCount,
|
fts5ApiPhraseCount,
|
||||||
fts5ApiPhraseSize,
|
fts5ApiPhraseSize,
|
||||||
|
fts5ApiInstCount,
|
||||||
|
fts5ApiInst,
|
||||||
fts5ApiRowid,
|
fts5ApiRowid,
|
||||||
fts5ApiColumnText,
|
fts5ApiColumnText,
|
||||||
fts5ApiColumnSize,
|
fts5ApiColumnSize,
|
||||||
|
@@ -70,13 +70,42 @@ typedef void (*fts5_extension_function)(
|
|||||||
** Returns the number of tokens in phrase iPhrase of the query. Phrases
|
** Returns the number of tokens in phrase iPhrase of the query. Phrases
|
||||||
** are numbered starting from zero.
|
** are numbered starting from zero.
|
||||||
**
|
**
|
||||||
|
** xInstCount:
|
||||||
|
** Set *pnInst to the total number of occurrences of all phrases within
|
||||||
|
** the query within the current row. Return SQLITE_OK if successful, or
|
||||||
|
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
|
||||||
|
**
|
||||||
|
** xInst:
|
||||||
|
** Query for the details of phrase match iIdx within the current row.
|
||||||
|
** Phrase matches are numbered starting from zero, so the iIdx argument
|
||||||
|
** should be greater than or equal to zero and smaller than the value
|
||||||
|
** output by xInstCount().
|
||||||
|
**
|
||||||
|
** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM)
|
||||||
|
** if an error occurs.
|
||||||
|
**
|
||||||
** xRowid:
|
** xRowid:
|
||||||
** Returns the rowid of the current row.
|
** Returns the rowid of the current row.
|
||||||
**
|
**
|
||||||
** xPoslist:
|
** xPoslist:
|
||||||
** Iterate through instances of phrase iPhrase in the current row.
|
** Iterate through phrase instances in the current row. If the iPhrase
|
||||||
|
** argument is 0 or greater, then only instances of phrase iPhrase are
|
||||||
|
** visited. If it is less than 0, instances of all phrases are visited.
|
||||||
|
**
|
||||||
|
** At EOF, -1 is returned and output variable iPos set to -1.
|
||||||
|
**
|
||||||
|
** </pre>
|
||||||
|
** sqlite3_int64 iPos;
|
||||||
|
** int iPhrase;
|
||||||
|
** int ii = 0;
|
||||||
|
**
|
||||||
|
** while( (iPhrase = pFts->xPoslist(pFts, -1, &ii, &iPos) >= 0 ){
|
||||||
|
** int iCol = FTS5_POS2COLUMN(iPos);
|
||||||
|
** int iOff = FTS5_POS2OFFSET(iPos);
|
||||||
|
** // An instance of phrase iPhrase at offset iOff of column iCol.
|
||||||
|
** }
|
||||||
|
** </pre>
|
||||||
**
|
**
|
||||||
** At EOF, a non-zero value is returned and output variable iPos set to -1.
|
|
||||||
**
|
**
|
||||||
** xTokenize:
|
** xTokenize:
|
||||||
** Tokenize text using the tokenizer belonging to the FTS5 table.
|
** Tokenize text using the tokenizer belonging to the FTS5 table.
|
||||||
@@ -160,6 +189,9 @@ struct Fts5ExtensionApi {
|
|||||||
int (*xPhraseCount)(Fts5Context*);
|
int (*xPhraseCount)(Fts5Context*);
|
||||||
int (*xPhraseSize)(Fts5Context*, int iPhrase);
|
int (*xPhraseSize)(Fts5Context*, int iPhrase);
|
||||||
|
|
||||||
|
int (*xInstCount)(Fts5Context*, int *pnInst);
|
||||||
|
int (*xInst)(Fts5Context*, int iIdx, int *piPhrase, int *piCol, int *piOff);
|
||||||
|
|
||||||
sqlite3_int64 (*xRowid)(Fts5Context*);
|
sqlite3_int64 (*xRowid)(Fts5Context*);
|
||||||
int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
|
int (*xColumnText)(Fts5Context*, int iCol, const char **pz, int *pn);
|
||||||
int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
|
int (*xColumnSize)(Fts5Context*, int iCol, int *pnToken);
|
||||||
|
@@ -301,6 +301,9 @@ void sqlite3Fts5IndexAutomerge(Fts5Index *p, int nMerge);
|
|||||||
*/
|
*/
|
||||||
int sqlite3Fts5IndexReads(Fts5Index *p);
|
int sqlite3Fts5IndexReads(Fts5Index *p);
|
||||||
|
|
||||||
|
/* Malloc utility */
|
||||||
|
void *sqlite3Fts5MallocZero(int *pRc, int nByte);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** End of interface to code in fts5_index.c.
|
** End of interface to code in fts5_index.c.
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
@@ -14,6 +14,138 @@
|
|||||||
#include "fts5Int.h"
|
#include "fts5Int.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
** Start of highlight() implementation.
|
||||||
|
*/
|
||||||
|
typedef struct HighlightContext HighlightContext;
|
||||||
|
struct HighlightContext {
|
||||||
|
const Fts5ExtensionApi *pApi; /* API offered by current FTS version */
|
||||||
|
Fts5Context *pFts; /* First arg to pass to pApi functions */
|
||||||
|
int iInst; /* Current phrase instance index */
|
||||||
|
int iStart; /* First token of current phrase */
|
||||||
|
int iEnd; /* Last token of current phrase */
|
||||||
|
|
||||||
|
const char *zOpen; /* Opening highlight */
|
||||||
|
const char *zClose; /* Closing highlight */
|
||||||
|
int iCol; /* Column to read from */
|
||||||
|
|
||||||
|
const char *zIn; /* Input text */
|
||||||
|
int nIn; /* Size of input text in bytes */
|
||||||
|
int iOff; /* Current offset within zIn[] */
|
||||||
|
char *zOut; /* Output value */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int fts5HighlightAppend(HighlightContext *p, const char *z, int n){
|
||||||
|
if( n<0 ) n = strlen(z);
|
||||||
|
p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z);
|
||||||
|
if( p->zOut==0 ) return SQLITE_NOMEM;
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fts5HighlightCb(
|
||||||
|
void *pContext, /* Pointer to HighlightContext object */
|
||||||
|
const char *pToken, /* Buffer containing token */
|
||||||
|
int nToken, /* Size of token in bytes */
|
||||||
|
int iStart, /* Start offset of token */
|
||||||
|
int iEnd, /* End offset of token */
|
||||||
|
int iPos /* Position offset of token */
|
||||||
|
){
|
||||||
|
HighlightContext *p = (HighlightContext*)pContext;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
|
if( iPos==p->iStart ){
|
||||||
|
rc = fts5HighlightAppend(p, &p->zIn[p->iOff], iStart - p->iOff);
|
||||||
|
p->iOff = iStart;
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = fts5HighlightAppend(p, p->zOpen, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = fts5HighlightAppend(p, &p->zIn[p->iOff], iEnd - p->iOff);
|
||||||
|
p->iOff = iEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && iPos==p->iEnd ){
|
||||||
|
int bClose = 1;
|
||||||
|
do{
|
||||||
|
int iP, iPCol, iOff;
|
||||||
|
rc = p->pApi->xInst(p->pFts, ++p->iInst, &iP, &iPCol, &iOff);
|
||||||
|
if( rc==SQLITE_RANGE || iPCol!=p->iCol ){
|
||||||
|
p->iStart = -1;
|
||||||
|
p->iEnd = -1;
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
}else{
|
||||||
|
iEnd = iOff - 1 + p->pApi->xPhraseSize(p->pFts, iP);
|
||||||
|
if( iEnd<=p->iEnd ) continue;
|
||||||
|
if( iOff<=p->iEnd ) bClose = 0;
|
||||||
|
p->iStart = iOff;
|
||||||
|
p->iEnd = iEnd;
|
||||||
|
}
|
||||||
|
}while( 0 );
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK && bClose ){
|
||||||
|
rc = fts5HighlightAppend(p, p->zClose, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fts5HighlightFunction(
|
||||||
|
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
|
||||||
|
Fts5Context *pFts, /* First arg to pass to pApi functions */
|
||||||
|
sqlite3_context *pCtx, /* Context for returning result/error */
|
||||||
|
int nVal, /* Number of values in apVal[] array */
|
||||||
|
sqlite3_value **apVal /* Array of trailing arguments */
|
||||||
|
){
|
||||||
|
HighlightContext ctx;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if( nVal!=3 ){
|
||||||
|
const char *zErr = "wrong number of arguments to function highlight()";
|
||||||
|
sqlite3_result_error(pCtx, zErr, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(&ctx, 0, sizeof(HighlightContext));
|
||||||
|
ctx.iCol = sqlite3_value_int(apVal[0]);
|
||||||
|
ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
|
||||||
|
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
|
||||||
|
rc = pApi->xColumnText(pFts, ctx.iCol, &ctx.zIn, &ctx.nIn);
|
||||||
|
ctx.pApi = pApi;
|
||||||
|
ctx.pFts = pFts;
|
||||||
|
|
||||||
|
/* Find the first phrase instance in the right column. */
|
||||||
|
ctx.iStart = -1;
|
||||||
|
ctx.iEnd = -1;
|
||||||
|
while( rc==SQLITE_OK ){
|
||||||
|
int iP, iPCol, iOff;
|
||||||
|
rc = pApi->xInst(pFts, ctx.iInst, &iP, &iPCol, &iOff);
|
||||||
|
if( rc==SQLITE_OK && iPCol==ctx.iCol ){
|
||||||
|
ctx.iStart = iOff;
|
||||||
|
ctx.iEnd = iOff - 1 + pApi->xPhraseSize(pFts, iP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ctx.iInst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK || rc==SQLITE_RANGE ){
|
||||||
|
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx, fts5HighlightCb);
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = fts5HighlightAppend(&ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_error_code(pCtx, rc);
|
||||||
|
}
|
||||||
|
sqlite3_free(ctx.zOut);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
typedef struct SnipPhrase SnipPhrase;
|
typedef struct SnipPhrase SnipPhrase;
|
||||||
typedef struct SnipIter SnipIter;
|
typedef struct SnipIter SnipIter;
|
||||||
typedef struct SnippetCtx SnippetCtx;
|
typedef struct SnippetCtx SnippetCtx;
|
||||||
@@ -796,6 +928,22 @@ static void fts5TestFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** xInst()
|
||||||
|
*/
|
||||||
|
if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " inst ");
|
||||||
|
if( 0==zReq || 0==sqlite3_stricmp(zReq, "inst") ){
|
||||||
|
int nInst;
|
||||||
|
rc = pApi->xInstCount(pFts, &nInst);
|
||||||
|
for(i=0; rc==SQLITE_OK && i<nInst; i++){
|
||||||
|
int iPhrase, iCol, iOff;
|
||||||
|
rc = pApi->xInst(pFts, i, &iPhrase, &iCol, &iOff);
|
||||||
|
sqlite3Fts5BufferAppendPrintf(&rc, &s, "%s%d.%d.%d",
|
||||||
|
(i==0 ? "" : " "), iPhrase, iCol, iOff
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** xPhraseCount()
|
** xPhraseCount()
|
||||||
*/
|
*/
|
||||||
@@ -966,6 +1114,7 @@ int sqlite3Fts5AuxInit(fts5_api *pApi){
|
|||||||
{ "bm25debug", (void*)1, fts5Bm25Function, 0 },
|
{ "bm25debug", (void*)1, fts5Bm25Function, 0 },
|
||||||
{ "snippet", 0, fts5SnippetFunction, 0 },
|
{ "snippet", 0, fts5SnippetFunction, 0 },
|
||||||
{ "fts5_test", 0, fts5TestFunction, 0 },
|
{ "fts5_test", 0, fts5TestFunction, 0 },
|
||||||
|
{ "highlight", 0, fts5HighlightFunction, 0 },
|
||||||
{ "bm25", 0, fts5Bm25Function, 0 },
|
{ "bm25", 0, fts5Bm25Function, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -692,7 +692,7 @@ static void *fts5IdxMalloc(Fts5Index *p, int nByte){
|
|||||||
return pRet;
|
return pRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *fts5MallocZero(int *pRc, int nByte){
|
void *sqlite3Fts5MallocZero(int *pRc, int nByte){
|
||||||
void *pRet = 0;
|
void *pRet = 0;
|
||||||
if( *pRc==SQLITE_OK ){
|
if( *pRc==SQLITE_OK ){
|
||||||
pRet = sqlite3_malloc(nByte);
|
pRet = sqlite3_malloc(nByte);
|
||||||
@@ -981,7 +981,7 @@ static int fts5StructureDecode(
|
|||||||
sizeof(Fts5Structure) + /* Main structure */
|
sizeof(Fts5Structure) + /* Main structure */
|
||||||
sizeof(Fts5StructureLevel) * (nLevel) /* aLevel[] array */
|
sizeof(Fts5StructureLevel) * (nLevel) /* aLevel[] array */
|
||||||
);
|
);
|
||||||
pRet = (Fts5Structure*)fts5MallocZero(&rc, nByte);
|
pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
|
||||||
|
|
||||||
if( pRet ){
|
if( pRet ){
|
||||||
pRet->nLevel = nLevel;
|
pRet->nLevel = nLevel;
|
||||||
@@ -995,7 +995,7 @@ static int fts5StructureDecode(
|
|||||||
i += getVarint32(&pData[i], pLvl->nMerge);
|
i += getVarint32(&pData[i], pLvl->nMerge);
|
||||||
i += getVarint32(&pData[i], nTotal);
|
i += getVarint32(&pData[i], nTotal);
|
||||||
assert( nTotal>=pLvl->nMerge );
|
assert( nTotal>=pLvl->nMerge );
|
||||||
pLvl->aSeg = (Fts5StructureSegment*)fts5MallocZero(&rc,
|
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
|
||||||
nTotal * sizeof(Fts5StructureSegment)
|
nTotal * sizeof(Fts5StructureSegment)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sthe\scustomization\sinterfaces\sso\sthat\sthey\smatch\sthe\sdocumentation.
|
C Add\sthe\sauxiliary\shighlight()\sfunction\sto\sfts5.
|
||||||
D 2014-11-15T20:07:31.166
|
D 2014-11-24T16:24:33.456
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
|
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
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/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
|
||||||
F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
|
F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
|
||||||
F ext/fts5/extract_api_docs.tcl 6320db4a1d0722a4e2069e661381ad75e9889786
|
F ext/fts5/extract_api_docs.tcl 6320db4a1d0722a4e2069e661381ad75e9889786
|
||||||
F ext/fts5/fts5.c cc3f0e4bac499c81d1311199f929dcad5e40ee8e
|
F ext/fts5/fts5.c d4b9895c5dc11c20493b3a9f09f4a0cdb0bc1438
|
||||||
F ext/fts5/fts5.h a77cad780eec8f10850fdba0f44079a92561b790
|
F ext/fts5/fts5.h 72fc1e9995b1ddc254a487b9528614a83bd3dfb6
|
||||||
F ext/fts5/fts5Int.h a3c46f9dae13277de6fc3a6f8863d337ca660d6a
|
F ext/fts5/fts5Int.h fd811979294410b10c1737392a9114510fc2a1be
|
||||||
F ext/fts5/fts5_aux.c 6b0612e4312ca27264f7dacb0c97abc723a4b472
|
F ext/fts5/fts5_aux.c 2e467bdd93f23f049824411b326f77b9326cb61a
|
||||||
F ext/fts5/fts5_buffer.c 248c61ac9fec001602efc72a45704f3b8d367c00
|
F ext/fts5/fts5_buffer.c 248c61ac9fec001602efc72a45704f3b8d367c00
|
||||||
F ext/fts5/fts5_config.c a292fe73864086e51e7974d842cc09f6379fbae0
|
F ext/fts5/fts5_config.c a292fe73864086e51e7974d842cc09f6379fbae0
|
||||||
F ext/fts5/fts5_expr.c d317be07d70223a6865444f17982570260b690a5
|
F ext/fts5/fts5_expr.c d317be07d70223a6865444f17982570260b690a5
|
||||||
F ext/fts5/fts5_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
|
F ext/fts5/fts5_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
|
||||||
F ext/fts5/fts5_index.c 3f4d84a1762e4284319739d4672b90b18b91060a
|
F ext/fts5/fts5_index.c 998c4aa0f003666afe85b6ff821476419ed245e9
|
||||||
F ext/fts5/fts5_storage.c 5913aa01a1dada1c5e1a39e4cbb44e84c5f7f350
|
F ext/fts5/fts5_storage.c 5913aa01a1dada1c5e1a39e4cbb44e84c5f7f350
|
||||||
F ext/fts5/fts5_tokenize.c 8360c0d1ae0d4696f3cc13f7c67a2db6011cdc5b
|
F ext/fts5/fts5_tokenize.c 8360c0d1ae0d4696f3cc13f7c67a2db6011cdc5b
|
||||||
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
|
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
|
||||||
@@ -602,12 +602,13 @@ F test/fts5aa.test 16bf1dbb92d4d63c7c357b480b1a47309f654ad1
|
|||||||
F test/fts5ab.test 657d6dc5ddc57bfea4af1bb85204d4f3539cd3e8
|
F test/fts5ab.test 657d6dc5ddc57bfea4af1bb85204d4f3539cd3e8
|
||||||
F test/fts5ac.test f38ceca8a43fa0ff86122bec72428a4067b17bc4
|
F test/fts5ac.test f38ceca8a43fa0ff86122bec72428a4067b17bc4
|
||||||
F test/fts5ad.test d29ff407c70df470c9a8fcbfe5bc80efd662f2c4
|
F test/fts5ad.test d29ff407c70df470c9a8fcbfe5bc80efd662f2c4
|
||||||
F test/fts5ae.test d4141786d817e0198f89f8c66749af38359839a7
|
F test/fts5ae.test a514ee09be90723ccc9736edaef900a5af1c121a
|
||||||
F test/fts5af.test d24e3b0f879998ef5f60087272f8ab7b3a8fd4dc
|
F test/fts5af.test d24e3b0f879998ef5f60087272f8ab7b3a8fd4dc
|
||||||
F test/fts5ag.test 1c6c188d1bdc41b2277db3f4ddfea7d90bf44ceb
|
F test/fts5ag.test 1c6c188d1bdc41b2277db3f4ddfea7d90bf44ceb
|
||||||
F test/fts5ah.test af9274cdb58a69780c7e57e61581990665ac0fb6
|
F test/fts5ah.test af9274cdb58a69780c7e57e61581990665ac0fb6
|
||||||
F test/fts5ai.test aa2b5fd0f8d2cf59ac0211111e63cbca3b40ed7d
|
F test/fts5ai.test aa2b5fd0f8d2cf59ac0211111e63cbca3b40ed7d
|
||||||
F test/fts5aj.test fe5c40216cac8072f29e454ee0540c7b89d17ccd
|
F test/fts5aj.test fe5c40216cac8072f29e454ee0540c7b89d17ccd
|
||||||
|
F test/fts5ak.test 2c930afe32bd15b39a2c416fabe9fc7a36e3042e
|
||||||
F test/fts5ea.test afaf3497b43add578384dc1fd26b0342738abe87
|
F test/fts5ea.test afaf3497b43add578384dc1fd26b0342738abe87
|
||||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||||
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
|
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
|
||||||
@@ -1204,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P e240d467e60b7755486aae5e8b0824f7c741f852
|
P fba0b5fc7eead07a4853e78e02d788e7c714f6cd
|
||||||
R 28baa98ae078d2f041a83a26b4550455
|
R 0f9755027ecd37d1e64800649e8a07f5
|
||||||
U dan
|
U dan
|
||||||
Z 1c1b566687b968f39cda6c2d32a692b6
|
Z 35a88e8d2ae30031588d0943e2aec6ce
|
||||||
|
@@ -1 +1 @@
|
|||||||
fba0b5fc7eead07a4853e78e02d788e7c714f6cd
|
059092379f981eb919b500ce447006f9e645fc5a
|
@@ -269,7 +269,7 @@ foreach {tn q res} {
|
|||||||
SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY +rank DESC;
|
SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY +rank DESC;
|
||||||
} $res
|
} $res
|
||||||
|
|
||||||
do_execsql_test 8.3.$tn.3 {
|
do_execsql_test 8.2.$tn.3 {
|
||||||
SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY rank DESC;
|
SELECT rowid FROM t8 WHERE t8 MATCH $q ORDER BY rank DESC;
|
||||||
} $res
|
} $res
|
||||||
}
|
}
|
||||||
|
111
test/fts5ak.test
Normal file
111
test/fts5ak.test
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# 2014 November 24
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# Specifically, the auxiliary function "highlight".
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix fts5aj
|
||||||
|
|
||||||
|
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
|
||||||
|
ifcapable !fts5 {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
CREATE VIRTUAL TABLE ft1 USING fts5(x);
|
||||||
|
INSERT INTO ft1 VALUES('i d d a g i b g d d');
|
||||||
|
INSERT INTO ft1 VALUES('h d b j c c g a c a');
|
||||||
|
INSERT INTO ft1 VALUES('e j a e f h b f h h');
|
||||||
|
INSERT INTO ft1 VALUES('j f h d g h i b d f');
|
||||||
|
INSERT INTO ft1 VALUES('d c j d c j b c g e');
|
||||||
|
INSERT INTO ft1 VALUES('i a d e g j g d a a');
|
||||||
|
INSERT INTO ft1 VALUES('j f c e d a h j d b');
|
||||||
|
INSERT INTO ft1 VALUES('i c c f a d g h j e');
|
||||||
|
INSERT INTO ft1 VALUES('i d i g c d c h b f');
|
||||||
|
INSERT INTO ft1 VALUES('g d a e h a b c f j');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.2 {
|
||||||
|
SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e';
|
||||||
|
} {
|
||||||
|
{g d a [e] h a b c f j}
|
||||||
|
{i c c f a d g h j [e]}
|
||||||
|
{j f c [e] d a h j d b}
|
||||||
|
{i a d [e] g j g d a a}
|
||||||
|
{d c j d c j b c g [e]}
|
||||||
|
{[e] j a [e] f h b f h h}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.3 {
|
||||||
|
SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'h + d';
|
||||||
|
} {
|
||||||
|
{j f [h d] g h i b d f}
|
||||||
|
{[h d] b j c c g a c a}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.4 {
|
||||||
|
SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d';
|
||||||
|
} {
|
||||||
|
{i [d d] a g i b g [d d]}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.5 {
|
||||||
|
SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e e e'
|
||||||
|
} {
|
||||||
|
{g d a [e] h a b c f j}
|
||||||
|
{i c c f a d g h j [e]}
|
||||||
|
{j f c [e] d a h j d b}
|
||||||
|
{i a d [e] g j g d a a}
|
||||||
|
{d c j d c j b c g [e]}
|
||||||
|
{[e] j a [e] f h b f h h}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.6 {
|
||||||
|
SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d d + d';
|
||||||
|
} {
|
||||||
|
{i [d d] a g i b g [d d]}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.1 {
|
||||||
|
CREATE VIRTUAL TABLE ft2 USING fts5(x);
|
||||||
|
INSERT INTO ft2 VALUES('a b c d e f g h i j');
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.2 {
|
||||||
|
SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d c+d+e'
|
||||||
|
} {{a [b c d e] f g h i j}}
|
||||||
|
|
||||||
|
do_execsql_test 2.3 {
|
||||||
|
SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d e+f+g'
|
||||||
|
} {
|
||||||
|
{a [b c d] [e f g] h i j}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.4 {
|
||||||
|
SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c+d c'
|
||||||
|
} {
|
||||||
|
{a [b c d] e f g h i j}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 2.5 {
|
||||||
|
SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'b+c c+d+e'
|
||||||
|
} {
|
||||||
|
{a [b c d e] f g h i j}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
Reference in New Issue
Block a user