typedef struct Fts5ExtensionApi Fts5ExtensionApi;
typedef struct Fts5Context Fts5Context;
+typedef struct Fts5PhraseIter Fts5PhraseIter;
typedef void (*fts5_extension_function)(
const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
sqlite3_value **apVal /* Array of trailing arguments */
);
+struct Fts5PhraseIter {
+ const unsigned char *a;
+ const unsigned char *b;
+};
+
/*
** EXTENSION API FUNCTIONS
**
** In other words, the same value that would be returned by:
**
** SELECT count(*) FROM ftstable;
+**
+** xPhraseFirst()
+** This function is used, along with type Fts5PhraseIter and the xPhraseNext
+** method, to iterate through all instances of a single query phrase within
+** the current row. This is the same information as is accessible via the
+** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
+** to use, this API may be faster under some circumstances. To iterate
+** through instances of phrase iPhrase, use the following code:
+**
+** Fts5PhraseIter iter;
+** int iCol, iOff;
+** for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
+** iOff>=0;
+** pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+** ){
+** // An instance of phrase iPhrase at offset iOff of column iCol
+** }
+**
+** The Fts5PhraseIter structure is defined above. Applications should not
+** modify this structure directly - it should only be used as shown above
+** with the xPhraseFirst() and xPhraseNext() API methods.
+**
+** xPhraseNext()
+** See xPhraseFirst above.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 1 */
);
int (*xSetAuxdata)(Fts5Context*, void *pAux, void(*xDelete)(void*));
void *(*xGetAuxdata)(Fts5Context*, int bClear);
+
+ void (*xPhraseFirst)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*, int*);
+ void (*xPhraseNext)(Fts5Context*, Fts5PhraseIter*, int *piCol, int *piOff);
};
/*
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
/* Cache used by auxiliary functions xInst() and xInstCount() */
+ Fts5PoslistReader *aInstIter; /* One for each phrase */
+ int nInstAlloc; /* Size of aInst[] array (entries / 3) */
int nInstCount; /* Number of phrase instances */
int *aInst; /* 3 integers per phrase instance */
};
Fts5Auxdata *pData;
Fts5Auxdata *pNext;
+ sqlite3_free(pCsr->aInstIter);
sqlite3_free(pCsr->aInst);
if( pCsr->pStmt ){
int eStmt = fts5StmtType(pCsr);
if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST) ){
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( pCsr->aInstIter==0 ){
+ int nByte = sizeof(Fts5PoslistReader) * nIter;
+ pCsr->aInstIter = (Fts5PoslistReader*)sqlite3Fts5MallocZero(&rc, nByte);
+ }
+ aIter = pCsr->aInstIter;
+
if( aIter ){
- Fts5Buffer buf = {0, 0, 0}; /* Build up aInst[] here */
int nInst = 0; /* Number instances seen so far */
int i;
iBest = i;
}
}
-
if( iBest<0 ) break;
+
nInst++;
- if( sqlite3Fts5BufferGrow(&rc, &buf, nInst * sizeof(int) * 3) ) break;
+ if( nInst>=pCsr->nInstAlloc ){
+ pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
+ aInst = (int*)sqlite3_realloc(
+ pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
+ );
+ if( aInst ){
+ pCsr->aInst = aInst;
+ }else{
+ rc = SQLITE_NOMEM;
+ break;
+ }
+ }
- aInst = &((int*)buf.p)[3 * (nInst-1)];
+ aInst = &pCsr->aInst[3 * (nInst-1)];
aInst[0] = iBest;
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
sqlite3Fts5PoslistReaderNext(&aIter[iBest]);
}
- sqlite3_free(pCsr->aInst);
- pCsr->aInst = (int*)buf.p;
pCsr->nInstCount = nInst;
- sqlite3_free(aIter);
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_INST);
}
}
return pRet;
}
+static void fts5ApiPhraseNext(
+ Fts5Context *pCtx,
+ Fts5PhraseIter *pIter,
+ int *piCol, int *piOff
+){
+ if( pIter->a>=pIter->b ){
+ *piCol = -1;
+ *piOff = -1;
+ }else{
+ int iVal;
+ pIter->a += fts5GetVarint32(pIter->a, iVal);
+ if( iVal==1 ){
+ pIter->a += fts5GetVarint32(pIter->a, iVal);
+ *piCol = iVal;
+ *piOff = 0;
+ pIter->a += fts5GetVarint32(pIter->a, iVal);
+ }
+ *piOff += (iVal-2);
+ }
+}
+
+static void fts5ApiPhraseFirst(
+ Fts5Context *pCtx,
+ int iPhrase,
+ Fts5PhraseIter *pIter,
+ int *piCol, int *piOff
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ int n = fts5CsrPoslist(pCsr, iPhrase, &pIter->a);
+ pIter->b = &pIter->a[n];
+ *piCol = 0;
+ *piOff = 0;
+ fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
+}
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
static const Fts5ExtensionApi sFts5Api = {
- 1, /* iVersion */
+ 2, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
fts5ApiQueryPhrase,
fts5ApiSetAuxdata,
fts5ApiGetAuxdata,
+ fts5ApiPhraseFirst,
+ fts5ApiPhraseNext,
};
Fts5Context *pFts,
void *pUserData
){
+ Fts5PhraseIter iter;
+ int iCol, iOff;
u32 *aOut = (u32*)pUserData;
- int nCol = pApi->xColumnCount(pFts);
- int nInst;
int iPrev = -1;
- int rc;
- int i;
- 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);
- aOut[iCol*3 + 1]++;
+ for(pApi->xPhraseFirst(pFts, 0, &iter, &iCol, &iOff);
+ iOff>=0;
+ pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+ ){
+ aOut[iCol*3+1]++;
if( iCol!=iPrev ) aOut[iCol*3 + 2]++;
iPrev = iCol;
}
- return rc;
+ return SQLITE_OK;
}
static int fts5MatchinfoGlobalCb(
case 'b':
case 'x':
case 'y': {
- int nInst;
int nMul = (f=='x' ? 3 : 1);
+ int iPhrase;
if( f=='b' ){
int nInt = ((p->nCol + 31) / 32) * p->nPhrase;
for(i=0; i<(p->nCol*p->nPhrase); i++) aOut[i*nMul] = 0;
}
- rc = pApi->xInstCount(pFts, &nInst);
- for(i=0; rc==SQLITE_OK && i<nInst; i++){
- int iPhrase, iOff, iCol = 0;
- rc = pApi->xInst(pFts, i, &iPhrase, &iCol, &iOff);
- if( f=='b' ){
- aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << (iCol%32));
- }else{
- aOut[nMul * (iCol + iPhrase * p->nCol)]++;
+ for(iPhrase=0; iPhrase<p->nPhrase; iPhrase++){
+ Fts5PhraseIter iter;
+ int iOff, iCol;
+ for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
+ iOff>=0;
+ pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
+ ){
+ if( f=='b' ){
+ aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32);
+ }else{
+ aOut[nMul * (iCol + iPhrase * p->nCol)]++;
+ }
}
}
/* If fts5_api_from_db() returns NULL, then either FTS5 is not registered
** with this database handle, or an error (OOM perhaps?) has occurred.
**
- ** Also check that the fts5_api object is version 1 or newer (there
- ** is no actual version of FTS5 that would return an API object of version
- ** 0, but FTS5 extensions should check the API version before using it). */
+ ** Also check that the fts5_api object is version 2 or newer.
+ */
if( pApi==0 || pApi->iVersion<1 ){
return SQLITE_ERROR;
}
-C Merge\sfixes\sfrom\sthe\sfts5NoWarn\sbranch.
-D 2015-08-11T14:25:34.036
+C Add\sthe\sxPhraseFirst()\sand\sxPhraseNext()\sfts5\sAPIs,\sfor\sfaster\siteration\sthrough\sa\ssingle\sphrases\sposition\slist.\sAlso\soptimize\sxInst()\sand\sxInstCount()\sa\sbit.
+D 2015-08-12T12:11:28.744
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2fc9ca6bf5949d415801c007ed3004a4bdb7c380
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts3/unicode/mkunicode.tcl 95cf7ec186e48d4985e433ff8a1c89090a774252
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
F ext/fts5/extract_api_docs.tcl 06583c935f89075ea0b32f85efa5dd7619fcbd03
-F ext/fts5/fts5.h 458a044344e96a7a3df38839f756aee105829303
+F ext/fts5/fts5.h 1950ec0544de667a24c1d8af9b2fde5db7db3bc9
F ext/fts5/fts5Int.h 45f2ceb3c030f70e2cc4c199e9f700c2f2367f77
F ext/fts5/fts5_aux.c 044cb176a815f4388308738437f6e130aa384fb0
F ext/fts5/fts5_buffer.c 80f9ba4431848cb857e3d2158f5280093dcd8015
F ext/fts5/fts5_expr.c 495b24f47f4d71b63339572a5beaf9f6e1b486fe
F ext/fts5/fts5_hash.c 4bf4b99708848357b8a2b5819e509eb6d3df9246
F ext/fts5/fts5_index.c 076c4995bf06a6d1559a6e31f9a86b90f2105374
-F ext/fts5/fts5_main.c 4c8af0015aaf1db2c81df4f617840a921360ef50
+F ext/fts5/fts5_main.c c5ff6eb7de5fe8e062b54bbee2b1936901533685
F ext/fts5/fts5_storage.c 22ec9b5d35a39e2b5b65daf4ba7cd47fbb2d0df5
F ext/fts5/fts5_tcl.c 96a3b9e982c4a64a242eefd752fa6669cd405a67
-F ext/fts5/fts5_test_mi.c c42a34590d9393d2aa0b959398261810ca976d05
+F ext/fts5/fts5_test_mi.c 80a9e86fb4c5b6b58f8fefac05e9b96d1a6574e1
F ext/fts5/fts5_tokenize.c 2836f6728bd74c7efac7487f5d9c27ca3e1b509c
F ext/fts5/fts5_unicode2.c 78273fbd588d1d9bd0a7e4e0ccc9207348bae33c
F ext/fts5/fts5_varint.c 3f86ce09cab152e3d45490d7586b7ed2e40c13f1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P fd5608fb20831f1f1946c8941445b7acc463a143 0ddb2532b2daaaf1b0109ac360822f84cb999b7f
-R f656c6f9b0efdad10e9de9eeca5d30e2
+P 61cb2fc6c12810863c965c74e90bc502e20cf810
+R d3b6dadb6d0d16c8d1ad296c14b96300
U dan
-Z a8d5c370bccbd577084eb4f30439c21a
+Z 2a4c5177ad3c19913de9e61965a0ba07
-61cb2fc6c12810863c965c74e90bc502e20cf810
\ No newline at end of file
+f7682435278419829a46bb4cc9b5625d46549e22
\ No newline at end of file