Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fixes and simplifications for the snippet() and highlight() functions. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | fts5 |
Files: | files | file ages | folders |
SHA1: |
ca5d44042aa7461dcc8b700b0763df4d |
User & Date: | dan 2014-12-22 21:01:52.167 |
Context
2014-12-23
| ||
19:18 | Fix the fts5 bm25() function so that it matches the documentation. (check-in: 1ac7a8d0af user: dan tags: fts5) | |
2014-12-22
| ||
21:01 | Fixes and simplifications for the snippet() and highlight() functions. (check-in: ca5d44042a user: dan tags: fts5) | |
2014-12-19
| ||
20:53 | Remove the fts5_test() aux function. Test aux functions using the tcl interface instead. (check-in: 67e3ffd950 user: dan tags: fts5) | |
Changes
Changes to ext/fts5/fts5.c.
︙ | ︙ | |||
1296 1297 1298 1299 1300 1301 1302 | if( pData ){ if( pData->xDelete ){ pData->xDelete(pData->pPtr); } }else{ pData = (Fts5Auxdata*)sqlite3_malloc(sizeof(Fts5Auxdata)); | | > > > | 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 | if( pData ){ if( pData->xDelete ){ pData->xDelete(pData->pPtr); } }else{ pData = (Fts5Auxdata*)sqlite3_malloc(sizeof(Fts5Auxdata)); if( pData==0 ){ if( xDelete ) xDelete(pPtr); return SQLITE_NOMEM; } memset(pData, 0, sizeof(Fts5Auxdata)); pData->pAux = pCsr->pAux; pData->pNext = pCsr->pAuxdata; pCsr->pAuxdata = pData; } pData->xDelete = xDelete; |
︙ | ︙ |
Changes to ext/fts5/fts5.h.
︙ | ︙ | |||
137 138 139 140 141 142 143 | ** xSetAuxdata(pFts5, pAux, xDelete) ** ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of ** of the same MATCH query using the xGetAuxdata() API. ** | | | > | > > > > > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | ** xSetAuxdata(pFts5, pAux, xDelete) ** ** Save the pointer passed as the second argument as the extension functions ** "auxiliary data". The pointer may then be retrieved by the current or any ** future invocation of the same fts5 extension function made as part of ** of the same MATCH query using the xGetAuxdata() API. ** ** Each extension function is allocated a single auxiliary data slot for ** each FTS query (MATCH expression). If the extension function is invoked ** more than once for a single FTS query, then all invocations share a ** single auxiliary data context. ** ** If there is already an auxiliary data pointer when this function is ** invoked, then it is replaced by the new pointer. If an xDelete callback ** was specified along with the original pointer, it is invoked at this ** point. ** ** The xDelete callback, if one is specified, is also invoked on the ** auxiliary data pointer after the FTS5 query has finished. ** ** If an error (e.g. an OOM condition) occurs within this function, an ** the auxiliary data is set to NULL and an error code returned. If the ** xDelete parameter was not NULL, it is invoked on the auxiliary data ** pointer before returning. ** ** ** xGetAuxdata(pFts5, bClear) ** ** Returns the current auxiliary data pointer for the fts5 extension ** function. See the xSetAuxdata() method for details. ** |
︙ | ︙ |
Changes to ext/fts5/fts5_aux.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #include "fts5Int.h" #include <math.h> /************************************************************************* ** Start of highlight() implementation. */ typedef struct HighlightContext HighlightContext; struct HighlightContext { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | | < < | < < > > > > > > > > > > > > | | < | < < | < < < > | | < | > > | < | | | < | > > > > > > > < < < | < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | | > > | > > > > > > | > > > > > | > > > | | | < | | > > > > > | > > | > | > > | > > > > | < > > > > > > > > | > | > > > | < < | | > > | < < | > > | > > > > > | > > | > > > > | > > | > > > | < > | < > > > > < | > > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | ** May you share freely, never taking more than you give. ** ****************************************************************************** */ #include "fts5Int.h" #include <math.h> /* ** Object used to iterate through all "coalesced phrase instances" in ** a single column of the current row. If the phrase instances in the ** column being considered do not overlap, this object simply iterates ** through them. Or, if they do overlap (share one or more tokens in ** common), each set of overlapping instances is treated as a single ** match. See documentation for the highlight() auxiliary function for ** details. ** ** Usage is: ** ** for(rc = fts5CInstIterNext(pApi, pFts, iCol, &iter); ** (rc==SQLITE_OK && 0==fts5CInstIterEof(&iter); ** rc = fts5CInstIterNext(&iter) ** ){ ** printf("instance starts at %d, ends at %d\n", iter.iStart, iter.iEnd); ** } ** */ typedef struct CInstIter CInstIter; struct CInstIter { const Fts5ExtensionApi *pApi; /* API offered by current FTS version */ Fts5Context *pFts; /* First arg to pass to pApi functions */ int iCol; /* Column to search */ int iInst; /* Next phrase instance index */ int nInst; /* Total number of phrase instances */ /* Output variables */ int iStart; /* First token in coalesced phrase instance */ int iEnd; /* Last token in coalesced phrase instance */ }; /* ** Return non-zero if the iterator is at EOF, or zero otherwise. */ static int fts5CInstIterEof(CInstIter *pIter){ return (pIter->iStart < 0); } /* ** Advance the iterator to the next coalesced phrase instance. Return ** an SQLite error code if an error occurs, or SQLITE_OK otherwise. */ static int fts5CInstIterNext(CInstIter *pIter){ int rc = SQLITE_OK; pIter->iStart = -1; pIter->iEnd = -1; while( rc==SQLITE_OK && pIter->iInst<pIter->nInst ){ int ip; int ic; int io; rc = pIter->pApi->xInst(pIter->pFts, pIter->iInst, &ip, &ic, &io); if( rc==SQLITE_OK ){ if( ic==pIter->iCol ){ int iEnd = io - 1 + pIter->pApi->xPhraseSize(pIter->pFts, ip); if( pIter->iStart<0 ){ pIter->iStart = io; pIter->iEnd = iEnd; }else if( io<=pIter->iEnd ){ if( iEnd>pIter->iEnd ) pIter->iEnd = iEnd; }else{ break; } } pIter->iInst++; } } return rc; } /* ** Initialize the iterator object indicated by the final parameter to ** iterate through coalesced phrase instances in column iCol. */ static int fts5CInstIterInit( const Fts5ExtensionApi *pApi, Fts5Context *pFts, int iCol, CInstIter *pIter ){ int rc; memset(pIter, 0, sizeof(CInstIter)); pIter->pApi = pApi; pIter->pFts = pFts; pIter->iCol = iCol; rc = pApi->xInstCount(pFts, &pIter->nInst); if( rc==SQLITE_OK ){ rc = fts5CInstIterNext(pIter); } return rc; } /************************************************************************* ** Start of highlight() implementation. */ typedef struct HighlightContext HighlightContext; struct HighlightContext { CInstIter iter; /* Coalesced Instance Iterator */ int iRangeStart; int iRangeEnd; const char *zOpen; /* Opening highlight */ const char *zClose; /* Closing highlight */ const char *zIn; /* Input text */ int nIn; /* Size of input text in bytes */ int iOff; /* Current offset within zIn[] */ char *zOut; /* Output value */ }; /* ** Append text to the HighlightContext output string - p->zOut. Argument ** z points to a buffer containing n bytes of text to append. If n is ** negative, everything up until the first '\0' is appended to the output. ** ** If *pRc is set to any value other than SQLITE_OK when this function is ** called, it is a no-op. If an error (i.e. an OOM condition) is encountered, ** *pRc is set to an error code before returning. */ static void fts5HighlightAppend( int *pRc, HighlightContext *p, const char *z, int n ){ if( *pRc==SQLITE_OK ){ if( n<0 ) n = strlen(z); p->zOut = sqlite3_mprintf("%z%.*s", p->zOut, n, z); if( p->zOut==0 ) *pRc = SQLITE_NOMEM; } } /* ** Tokenizer callback used by implementation of highlight() function. */ static int fts5HighlightCb( void *pContext, /* Pointer to HighlightContext object */ const char *pToken, /* Buffer containing token */ int nToken, /* Size of token in bytes */ int iStartOff, /* Start offset of token */ int iEndOff, /* End offset of token */ int iPos /* Position offset of token */ ){ HighlightContext *p = (HighlightContext*)pContext; int rc = SQLITE_OK; if( p->iRangeEnd>0 ){ if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK; if( iPos==p->iRangeStart ) p->iOff = iStartOff; } if( iPos==p->iter.iStart ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff); fts5HighlightAppend(&rc, p, p->zOpen, -1); p->iOff = iStartOff; } if( iPos==p->iter.iEnd ){ if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){ fts5HighlightAppend(&rc, p, p->zOpen, -1); } fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); fts5HighlightAppend(&rc, p, p->zClose, -1); p->iOff = iEndOff; if( rc==SQLITE_OK ){ rc = fts5CInstIterNext(&p->iter); } } if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff); p->iOff = iEndOff; if( iPos<p->iter.iEnd ){ fts5HighlightAppend(&rc, p, p->zClose, -1); } } return rc; } /* ** Implementation of highlight() function. */ 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; int iCol; if( nVal!=3 ){ const char *zErr = "wrong number of arguments to function highlight()"; sqlite3_result_error(pCtx, zErr, -1); return; } iCol = sqlite3_value_int(apVal[0]); memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx, fts5HighlightCb); } fts5HighlightAppend(&rc, &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); } /* **************************************************************************/ static void fts5SnippetFunction( 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 = SQLITE_OK; /* Return code */ int iCol; /* 1st argument to snippet() */ const char *zEllips; /* 4th argument to snippet() */ int nToken; /* 5th argument to snippet() */ int nInst; /* Number of instance matches this row */ int i; /* Used to iterate through instances */ int nPhrase; /* Number of phrases in query */ unsigned char *aSeen; /* Array of "seen instance" flags */ int iBestCol; /* Column containing best snippet */ int iBestStart = 0; /* First token of best snippet */ int iBestLast = nToken; /* Last token of best snippet */ int nBestScore = 0; /* Score of best snippet */ int nColSize; /* Total size of iBestCol in tokens */ if( nVal!=5 ){ const char *zErr = "wrong number of arguments to function snippet()"; sqlite3_result_error(pCtx, zErr, -1); return; } memset(&ctx, 0, sizeof(HighlightContext)); rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); zEllips = (const char*)sqlite3_value_text(apVal[3]); nToken = sqlite3_value_int(apVal[4]); iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); aSeen = sqlite3_malloc(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ rc = pApi->xInstCount(pFts, &nInst); } for(i=0; rc==SQLITE_OK && i<nInst; i++){ int ip, iSnippetCol, iStart; memset(aSeen, 0, nPhrase); rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart); if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){ int nScore = 1000; int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip); int j; aSeen[ip] = 1; for(j=i+1; rc==SQLITE_OK && j<nInst; j++){ int ic; int io; int iFinal; rc = pApi->xInst(pFts, j, &ip, &ic, &io); iFinal = io + pApi->xPhraseSize(pFts, ip) - 1; if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){ nScore += aSeen[ip] ? 1000 : 1; aSeen[ip] = 1; if( iFinal>iLast ) iLast = iFinal; } } if( rc==SQLITE_OK && nScore>nBestScore ){ iBestCol = iSnippetCol; iBestStart = iStart; iBestLast = iLast; nBestScore = nScore; } } } if( rc==SQLITE_OK ){ rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); } if( rc==SQLITE_OK ){ rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); } if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); } if( (iBestStart+nToken-1)>iBestLast ){ iBestStart -= (iBestStart+nToken-1-iBestLast) / 2; } if( iBestStart+nToken>nColSize ){ iBestStart = nColSize - nToken; } if( iBestStart<0 ) iBestStart = 0; ctx.iRangeStart = iBestStart; ctx.iRangeEnd = iBestStart + nToken - 1; if( iBestStart>0 ){ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx, fts5HighlightCb); } if( ctx.iRangeEnd>=(nColSize-1) ){ fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); }else{ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } 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); sqlite3_free(aSeen); } /************************************************************************/ /* ** Context object passed by fts5GatherTotals() to xQueryPhrase callback ** fts5GatherCallback(). */ struct Fts5GatherCtx { |
︙ | ︙ |
Changes to ext/fts5/fts5_tcl.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 | }; typedef struct F5tApi F5tApi; struct F5tApi { const Fts5ExtensionApi *pApi; Fts5Context *pFts; }; static int xTokenizeCb( void *pCtx, const char *zToken, int nToken, int iStart, int iEnd, int iPos ){ F5tFunction *p = (F5tFunction*)pCtx; | > > > > > > > > > > > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | }; typedef struct F5tApi F5tApi; struct F5tApi { const Fts5ExtensionApi *pApi; Fts5Context *pFts; }; /* ** An object of this type is used with the xSetAuxdata() and xGetAuxdata() ** API test wrappers. The tcl interface allows a single tcl value to be ** saved using xSetAuxdata(). Instead of simply storing a pointer to the ** tcl object, the code in this file wraps it in an sqlite3_malloc'd ** instance of the following struct so that if the destructor is not ** correctly invoked it will be reported as an SQLite memory leak. */ typedef struct F5tAuxData F5tAuxData; struct F5tAuxData { Tcl_Obj *pObj; }; static int xTokenizeCb( void *pCtx, const char *zToken, int nToken, int iStart, int iEnd, int iPos ){ F5tFunction *p = (F5tFunction*)pCtx; |
︙ | ︙ | |||
103 104 105 106 107 108 109 110 111 | Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zCmd, -1)); rc = Tcl_EvalObjEx(p->interp, pEval, 0); Tcl_DecrRefCount(pEval); Tcl_DeleteCommand(p->interp, zCmd); return rc; } /* | > > > > > > | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zCmd, -1)); rc = Tcl_EvalObjEx(p->interp, pEval, 0); Tcl_DecrRefCount(pEval); Tcl_DeleteCommand(p->interp, zCmd); return rc; } static void xSetAuxdataDestructor(void *p){ F5tAuxData *pData = (F5tAuxData*)p; Tcl_DecrRefCount(pData->pObj); sqlite3_free(pData); } /* ** api sub-command... ** ** Description... */ static int xF5tApi( void * clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ | |||
132 133 134 135 136 137 138 139 140 141 142 143 144 145 | { "xPhraseSize", 1, "PHRASE" }, { "xInstCount", 0, "" }, { "xInst", 1, "IDX" }, { "xRowid", 0, "" }, { "xColumnText", 1, "COL" }, { "xColumnSize", 1, "COL" }, { "xQueryPhrase", 2, "PHRASE SCRIPT" }, { 0, 0, 0} }; int rc; int iSub = 0; F5tApi *p = (F5tApi*)clientData; | > > | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | { "xPhraseSize", 1, "PHRASE" }, { "xInstCount", 0, "" }, { "xInst", 1, "IDX" }, { "xRowid", 0, "" }, { "xColumnText", 1, "COL" }, { "xColumnSize", 1, "COL" }, { "xQueryPhrase", 2, "PHRASE SCRIPT" }, { "xSetAuxdata", 1, "VALUE" }, { "xGetAuxdata", 1, "CLEAR" }, { 0, 0, 0} }; int rc; int iSub = 0; F5tApi *p = (F5tApi*)clientData; |
︙ | ︙ | |||
277 278 279 280 281 282 283 284 285 286 287 288 289 290 | return TCL_ERROR; } ctx.interp = interp; ctx.pScript = objv[3]; rc = p->pApi->xQueryPhrase(p->pFts, iPhrase, &ctx, xQueryPhraseCb); if( rc==SQLITE_OK ){ Tcl_ResetResult(interp); } break; } default: assert( 0 ); break; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | return TCL_ERROR; } ctx.interp = interp; ctx.pScript = objv[3]; rc = p->pApi->xQueryPhrase(p->pFts, iPhrase, &ctx, xQueryPhraseCb); if( rc==SQLITE_OK ){ Tcl_ResetResult(interp); } break; } CASE(12, "xSetAuxdata") { F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData)); if( pData==0 ){ Tcl_AppendResult(interp, "out of memory", 0); return TCL_ERROR; } pData->pObj = objv[2]; Tcl_IncrRefCount(pData->pObj); rc = p->pApi->xSetAuxdata(p->pFts, pData, xSetAuxdataDestructor); break; } CASE(13, "xGetAuxdata") { F5tAuxData *pData; int bClear; if( Tcl_GetBooleanFromObj(interp, objv[2], &bClear) ){ return TCL_ERROR; } pData = (F5tAuxData*)p->pApi->xGetAuxdata(p->pFts, bClear); if( pData==0 ){ Tcl_ResetResult(interp); }else{ Tcl_SetObjResult(interp, pData->pObj); if( bClear ){ xSetAuxdataDestructor((void*)pData); } } break; } default: assert( 0 ); break; |
︙ | ︙ |
Added ext/fts5/fts5auxdata.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # 2014 Dec 20 # # 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. # #*********************************************************************** # # Tests focusing on the fts5 xSetAuxdata() and xGetAuxdata() APIs. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set testprefix fts5auxdata do_execsql_test 1.0 { CREATE VIRTUAL TABLE f1 USING fts5(a, b); INSERT INTO f1(rowid, a, b) VALUES(1, 'a', 'b1'); INSERT INTO f1(rowid, a, b) VALUES(2, 'a', 'b2'); INSERT INTO f1(rowid, a, b) VALUES(3, 'a', 'b3'); INSERT INTO f1(rowid, a, b) VALUES(4, 'a', 'b4'); INSERT INTO f1(rowid, a, b) VALUES(5, 'a', 'b5'); } proc aux_function_1 {cmd tn} { switch [$cmd xRowid] { 1 { do_test $tn.1 [list $cmd xGetAuxdata 0 ] {} $cmd xSetAuxdata "one" } 2 { do_test $tn.2 [list $cmd xGetAuxdata 0 ] {one} $cmd xSetAuxdata "two" } 3 { do_test $tn.3 [list $cmd xGetAuxdata 0 ] {two} } 4 { do_test $tn.4 [list $cmd xGetAuxdata 1 ] {two} } 5 { do_test $tn.5 [list $cmd xGetAuxdata 0 ] {} } } } sqlite3_fts5_create_function db aux_function_1 aux_function_1 db eval { SELECT aux_function_1(f1, 1) FROM f1 WHERE f1 MATCH 'a' ORDER BY rowid ASC } proc aux_function_2 {cmd tn inst} { if {$inst == "A"} { switch [$cmd xRowid] { 1 { do_test $tn.1.$inst [list $cmd xGetAuxdata 0 ] {} $cmd xSetAuxdata "one $inst" } 2 { do_test $tn.2.$inst [list $cmd xGetAuxdata 0 ] "one $inst" $cmd xSetAuxdata "two $inst" } 3 { do_test $tn.3.$inst [list $cmd xGetAuxdata 0 ] "two $inst" } 4 { do_test $tn.4.$inst [list $cmd xGetAuxdata 1 ] "two $inst" } 5 { do_test $tn.5.$inst [list $cmd xGetAuxdata 0 ] {} } } } else { switch [$cmd xRowid] { 1 { do_test $tn.1.$inst [list $cmd xGetAuxdata 0 ] "one A" } 2 { do_test $tn.2.$inst [list $cmd xGetAuxdata 0 ] "two A" } 3 { do_test $tn.3.$inst [list $cmd xGetAuxdata 0 ] "two A" } 4 { do_test $tn.4.$inst [list $cmd xGetAuxdata 0 ] {} } 5 { do_test $tn.5.$inst [list $cmd xGetAuxdata 0 ] {} } } } } sqlite3_fts5_create_function db aux_function_2 aux_function_2 db eval { SELECT aux_function_2(f1, 2, 'A'), aux_function_2(f1, 2, 'B') FROM f1 WHERE f1 MATCH 'a' ORDER BY rowid ASC } finish_test |
Changes to test/fts5af.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | uplevel #0 [list set v1 $doc] uplevel #0 [list set v2 $match] do_execsql_test $tn.1 { DELETE FROM t1; INSERT INTO t1 VALUES($v1, NULL); | | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | uplevel #0 [list set v1 $doc] uplevel #0 [list set v2 $match] do_execsql_test $tn.1 { DELETE FROM t1; INSERT INTO t1 VALUES($v1, NULL); SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2; } [list $res] do_execsql_test $tn.2 { DELETE FROM t1; INSERT INTO t1 VALUES(NULL, $v1); SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2; } [list $res] do_execsql_test $tn.3 { DELETE FROM t1; INSERT INTO t1 VALUES($v1, NULL); SELECT snippet(t1, -1, '[', ']', '...', 7) FROM t1 WHERE t1 MATCH $v2 ORDER BY rank DESC; } [list $res] } |
︙ | ︙ |
Changes to test/fts5ak.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # focus of this script is testing the FTS5 module. # # Specifically, the auxiliary function "highlight". # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # 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 fts5ak # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test return } |
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 | } do_execsql_test 2.6.2 { SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'd f' } { {a b c [d] e [f] g h i j} } finish_test | > > > > > > > > > > > > > > > > > > > > > | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | } do_execsql_test 2.6.2 { SELECT highlight(ft2, 0, '[', ']') FROM ft2 WHERE ft2 MATCH 'd f' } { {a b c [d] e [f] g h i j} } #------------------------------------------------------------------------- # The example from the docs. # do_execsql_test 3.1 { -- Assuming this: CREATE VIRTUAL TABLE ft USING fts5(a); INSERT INTO ft VALUES('a b c x c d e'); INSERT INTO ft VALUES('a b c c d e'); INSERT INTO ft VALUES('a b c d e'); -- The following SELECT statement returns these three rows: -- '[a b c] x [c d e]' -- '[a b c] [c d e]' -- '[a b c d e]' SELECT highlight(ft, 0, '[', ']') FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; } { {[a b c d e]} {[a b c] [c d e]} {[a b c] x [c d e]} } finish_test |