struct Fts5Data {
u8 *p; /* Pointer to buffer containing record */
int n; /* Size of record in bytes */
- int nRef; /* Ref count */
};
/*
};
struct Fts5DoclistIter {
- int bDesc; /* True for DESC order, false for ASC */
u8 *a;
int n;
int i;
Fts5Index *pIndex;
Fts5Structure *pStruct;
Fts5MultiSegIter *pMulti;
- Fts5DoclistIter *pDoclist;
Fts5Buffer poslist; /* Buffer containing current poslist */
};
if( pRet ){
pRet->n = nByte;
aOut = pRet->p = (u8*)&pRet[1];
- pRet->nRef = 1;
}
}
** fts5DataRead().
*/
static void fts5DataRelease(Fts5Data *pData){
- if( pData ){
- assert( pData->nRef>0 );
- pData->nRef--;
- if( pData->nRef==0 ) sqlite3_free(pData);
- }
-}
-
-static void fts5DataReference(Fts5Data *pData){
- pData->nRef++;
+ sqlite3_free(pData);
}
/*
sqlite3Fts5BufferSet(&p->rc, &pIter->term, n, z);
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
if( pLeaf==0 ) return;
- pLeaf->nRef = 1;
pLeaf->p = (u8*)pList;
pLeaf->n = nList;
pIter->pLeaf = pLeaf;
}
}
+static Fts5MultiSegIter *fts5MultiIterAlloc(
+ Fts5Index *p, /* FTS5 backend to iterate within */
+ int nSeg
+){
+ Fts5MultiSegIter *pNew;
+ int nSlot; /* Power of two >= nSeg */
+
+ for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
+ pNew = fts5IdxMalloc(p,
+ sizeof(Fts5MultiSegIter) + /* pNew */
+ sizeof(Fts5SegIter) * nSlot + /* pNew->aSeg[] */
+ sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
+ );
+ if( pNew ){
+ pNew->nSeg = nSlot;
+ pNew->aSeg = (Fts5SegIter*)&pNew[1];
+ pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
+ }
+ return pNew;
+}
+
/*
** Allocate a new Fts5MultiSegIter object.
**
Fts5MultiSegIter **ppOut /* New object */
){
int nSeg; /* Number of segment-iters in use */
- int nSlot = 0; /* Power of two >= nSeg */
int iIter = 0; /* */
int iSeg; /* Used to iterate through segments */
Fts5StructureLevel *pLvl;
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
- for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
}
-
- *ppOut = pNew = fts5IdxMalloc(p,
- sizeof(Fts5MultiSegIter) + /* pNew */
- sizeof(Fts5SegIter) * nSlot + /* pNew->aSeg[] */
- sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
- );
+ *ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
if( pNew==0 ) return;
- pNew->nSeg = nSlot;
- pNew->aSeg = (Fts5SegIter*)&pNew[1];
- pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
pNew->bSkipEmpty = bSkipEmpty;
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
- for(iIter=nSlot-1; iIter>0; iIter--){
+ for(iIter=pNew->nSeg-1; iIter>0; iIter--){
int iEq;
if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
fts5SegIterNext(p, &pNew->aSeg[iEq], 0);
}
}
+/*
+** Create an Fts5MultiSegIter that iterates through the doclist provided
+** as the second argument.
+*/
+static void fts5MultiIterNew2(
+ Fts5Index *p, /* FTS5 backend to iterate within */
+ Fts5Data *pData, /* Doclist to iterate through */
+ int bDesc, /* True for descending rowid order */
+ Fts5MultiSegIter **ppOut /* New object */
+){
+ Fts5MultiSegIter *pNew;
+ pNew = fts5MultiIterAlloc(p, 2);
+ if( pNew ){
+ Fts5SegIter *pIter = &pNew->aSeg[1];
+
+ pIter->flags = FTS5_SEGITER_ONETERM;
+ if( pData->n>0 ){
+ pIter->pLeaf = pData;
+ pIter->iLeafOffset = getVarint(pData->p, (u64*)&pIter->iRowid);
+ pNew->aFirst[1].iFirst = 1;
+ if( bDesc ){
+ pNew->bRev = 1;
+ pIter->flags |= FTS5_SEGITER_REVERSE;
+ fts5SegIterReverseInitPage(p, pIter);
+ }else{
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ pData = 0;
+ }
+
+ *ppOut = pNew;
+ }
+
+ fts5DataRelease(pData);
+}
+
/*
** Return true if the iterator is at EOF or if an error has occurred.
** False otherwise.
if( pIter->i ){
i64 iDelta;
pIter->i += getVarint(&pIter->a[pIter->i], (u64*)&iDelta);
- if( pIter->bDesc ){
- pIter->iRowid -= iDelta;
- }else{
- pIter->iRowid += iDelta;
- }
+ pIter->iRowid += iDelta;
}else{
pIter->i += getVarint(&pIter->a[pIter->i], (u64*)&pIter->iRowid);
}
static void fts5DoclistIterInit(
Fts5Buffer *pBuf,
- int bDesc,
Fts5DoclistIter *pIter
){
memset(pIter, 0, sizeof(*pIter));
pIter->a = pBuf->p;
pIter->n = pBuf->n;
- pIter->bDesc = bDesc;
fts5DoclistIterNext(pIter);
}
*/
static void fts5MergeAppendDocid(
int *pRc, /* IN/OUT: Error code */
- int bDesc,
Fts5Buffer *pBuf, /* Buffer to write to */
i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */
i64 iRowid /* Rowid to append */
){
if( pBuf->n==0 ){
fts5BufferAppendVarint(pRc, pBuf, iRowid);
- }else if( bDesc ){
- fts5BufferAppendVarint(pRc, pBuf, *piLastRowid - iRowid);
}else{
fts5BufferAppendVarint(pRc, pBuf, iRowid - *piLastRowid);
}
*/
static void fts5MergePrefixLists(
Fts5Index *p, /* FTS5 backend object */
- int bDesc,
Fts5Buffer *p1, /* First list to merge */
Fts5Buffer *p2 /* Second list to merge */
){
memset(&out, 0, sizeof(out));
memset(&tmp, 0, sizeof(tmp));
- fts5DoclistIterInit(p1, bDesc, &i1);
- fts5DoclistIterInit(p2, bDesc, &i2);
+ fts5DoclistIterInit(p1, &i1);
+ fts5DoclistIterInit(p2, &i2);
while( p->rc==SQLITE_OK && (i1.aPoslist!=0 || i2.aPoslist!=0) ){
- if( i2.aPoslist==0 || (i1.aPoslist &&
- ( (bDesc && i1.iRowid>i2.iRowid) || (!bDesc && i1.iRowid<i2.iRowid) )
- )){
+ if( i2.aPoslist==0 || (i1.aPoslist && i1.iRowid<i2.iRowid) ){
/* Copy entry from i1 */
- fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i1.iRowid);
+ fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i1.iRowid);
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, &out, i1.nPoslist * 2);
fts5BufferAppendBlob(&p->rc, &out, i1.nPoslist, i1.aPoslist);
}
else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){
/* Copy entry from i2 */
- fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i2.iRowid);
+ fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i2.iRowid);
/* WRITEPOSLISTSIZE */
fts5BufferAppendVarint(&p->rc, &out, i2.nPoslist * 2);
fts5BufferAppendBlob(&p->rc, &out, i2.nPoslist, i2.aPoslist);
memset(&writer, 0, sizeof(writer));
/* Merge the two position lists. */
- fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i2.iRowid);
+ fts5MergeAppendDocid(&p->rc, &out, &iLastRowid, i2.iRowid);
fts5BufferZero(&tmp);
sqlite3Fts5PoslistReaderInit(-1, i1.aPoslist, i1.nPoslist, &r1);
sqlite3Fts5PoslistReaderInit(-1, i2.aPoslist, i2.nPoslist, &r2);
if( aBuf && pStruct ){
const int flags = FTS5INDEX_QUERY_SCAN;
- Fts5DoclistIter *pDoclist;
int i;
i64 iLastRowid = 0;
Fts5MultiSegIter *p1 = 0; /* Iterator used to gather data from index */
+ Fts5Data *pData;
Fts5Buffer doclist;
memset(&doclist, 0, sizeof(doclist));
assert( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
- if( doclist.n>0
- && ((!bDesc && iRowid<=iLastRowid) || (bDesc && iRowid>=iLastRowid))
- ){
-
+ if( doclist.n>0 && iRowid<=iLastRowid ){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
assert( i<nBuf );
if( aBuf[i].n==0 ){
fts5BufferSwap(&doclist, &aBuf[i]);
fts5BufferZero(&doclist);
}else{
- fts5MergePrefixLists(p, bDesc, &doclist, &aBuf[i]);
+ fts5MergePrefixLists(p, &doclist, &aBuf[i]);
fts5BufferZero(&aBuf[i]);
}
}
}
- if( doclist.n==0 ){
- fts5BufferAppendVarint(&p->rc, &doclist, iRowid);
- }else if( bDesc ){
- fts5BufferAppendVarint(&p->rc, &doclist, iLastRowid - iRowid);
- }else{
- fts5BufferAppendVarint(&p->rc, &doclist, iRowid - iLastRowid);
- }
- iLastRowid = iRowid;
+
+ fts5MergeAppendDocid(&p->rc, &doclist, &iLastRowid, iRowid);
fts5MultiIterPoslist(p, p1, 1, &doclist);
}
for(i=0; i<nBuf; i++){
- fts5MergePrefixLists(p, bDesc, &doclist, &aBuf[i]);
+ fts5MergePrefixLists(p, &doclist, &aBuf[i]);
fts5BufferFree(&aBuf[i]);
}
fts5MultiIterFree(p, p1);
- pDoclist = (Fts5DoclistIter*)fts5IdxMalloc(p, sizeof(Fts5DoclistIter));
- if( !pDoclist ){
- fts5BufferFree(&doclist);
- }else{
- pIter->pDoclist = pDoclist;
- fts5DoclistIterInit(&doclist, bDesc, pIter->pDoclist);
+ pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n);
+ if( pData ){
+ pData->p = (u8*)&pData[1];
+ pData->n = doclist.n;
+ memcpy(pData->p, doclist.p, doclist.n);
+ fts5MultiIterNew2(p, pData, bDesc, &pIter->pMulti);
}
+ fts5BufferFree(&doclist);
}
fts5StructureRelease(pStruct);
*/
int sqlite3Fts5IterEof(Fts5IndexIter *pIter){
assert( pIter->pIndex->rc==SQLITE_OK );
- if( pIter->pDoclist ){
- return pIter->pDoclist->aPoslist==0;
- }else{
- return fts5MultiIterEof(pIter->pIndex, pIter->pMulti);
- }
+ return fts5MultiIterEof(pIter->pIndex, pIter->pMulti);
}
/*
*/
int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
assert( pIter->pIndex->rc==SQLITE_OK );
- if( pIter->pDoclist ){
- fts5DoclistIterNext(pIter->pDoclist);
- }else{
- fts5BufferZero(&pIter->poslist);
- fts5MultiIterNext(pIter->pIndex, pIter->pMulti, 0, 0);
- }
+ fts5BufferZero(&pIter->poslist);
+ fts5MultiIterNext(pIter->pIndex, pIter->pMulti, 0, 0);
return fts5IndexReturn(pIter->pIndex);
}
return fts5IndexReturn(pIter->pIndex);
}
-/*
-** Move the doclist-iter passed as the first argument to the next
-** matching rowid that occurs at or after iMatch. The definition of "at
-** or after" depends on whether this iterator iterates in ascending or
-** descending rowid order.
-*/
-static void fts5DoclistIterNextFrom(Fts5DoclistIter *p, i64 iMatch){
- do{
- i64 iRowid = p->iRowid;
- if( p->bDesc==0 && iRowid>=iMatch ) break;
- if( p->bDesc!=0 && iRowid<=iMatch ) break;
- fts5DoclistIterNext(p);
- }while( p->aPoslist );
-}
-
/*
** Move to the next matching rowid that occurs at or after iMatch. The
** definition of "at or after" depends on whether this iterator iterates
** in ascending or descending rowid order.
*/
int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIter, i64 iMatch){
- if( pIter->pDoclist ){
- fts5DoclistIterNextFrom(pIter->pDoclist, iMatch);
- }else{
- fts5MultiIterNextFrom(pIter->pIndex, pIter->pMulti, iMatch);
- }
+ fts5MultiIterNextFrom(pIter->pIndex, pIter->pMulti, iMatch);
return fts5IndexReturn(pIter->pIndex);
}
** Return the current rowid.
*/
i64 sqlite3Fts5IterRowid(Fts5IndexIter *pIter){
- if( pIter->pDoclist ){
- return pIter->pDoclist->iRowid;
- }else{
- return fts5MultiIterRowid(pIter->pMulti);
- }
+ return fts5MultiIterRowid(pIter->pMulti);
}
/*
int *pn, /* OUT: Size of position-list in bytes */
i64 *piRowid /* OUT: Current rowid */
){
- Fts5DoclistIter *pDoclist = pIter->pDoclist;
+ Fts5MultiSegIter *pMulti = pIter->pMulti;
+ Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
assert( pIter->pIndex->rc==SQLITE_OK );
- if( pDoclist ){
- *pn = pDoclist->nPoslist;
- *pp = pDoclist->aPoslist;
- *piRowid = pDoclist->iRowid;
+ *piRowid = pSeg->iRowid;
+ *pn = pSeg->nPos;
+ if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->n ){
+ *pp = &pSeg->pLeaf->p[pSeg->iLeafOffset];
}else{
- Fts5MultiSegIter *pMulti = pIter->pMulti;
- Fts5SegIter *pSeg = &pMulti->aSeg[ pMulti->aFirst[1].iFirst ];
- *piRowid = pSeg->iRowid;
- *pn = pSeg->nPos;
- if( pSeg->iLeafOffset+pSeg->nPos <= pSeg->pLeaf->n ){
- *pp = &pSeg->pLeaf->p[pSeg->iLeafOffset];
- }else{
- fts5BufferZero(&pIter->poslist);
- fts5SegiterPoslist(pIter->pIndex, pSeg, &pIter->poslist);
- *pp = pIter->poslist.p;
- }
+ fts5BufferZero(&pIter->poslist);
+ fts5SegiterPoslist(pIter->pIndex, pSeg, &pIter->poslist);
+ *pp = pIter->poslist.p;
}
return fts5IndexReturn(pIter->pIndex);
}
*/
int sqlite3Fts5IterPoslistBuffer(Fts5IndexIter *pIter, Fts5Buffer *pBuf){
Fts5Index *p = pIter->pIndex;
- Fts5DoclistIter *pDoclist = pIter->pDoclist;
+ Fts5MultiSegIter *pMulti = pIter->pMulti;
+
assert( p->rc==SQLITE_OK );
- if( pDoclist ){
- fts5BufferSet(&p->rc, pBuf, pDoclist->nPoslist, pDoclist->aPoslist);
- }else{
- Fts5MultiSegIter *pMulti = pIter->pMulti;
- fts5BufferZero(pBuf);
- fts5MultiIterPoslist(p, pMulti, 0, pBuf);
- }
+ fts5BufferZero(pBuf);
+ fts5MultiIterPoslist(p, pMulti, 0, pBuf);
return fts5IndexReturn(p);
}
*/
void sqlite3Fts5IterClose(Fts5IndexIter *pIter){
if( pIter ){
- if( pIter->pDoclist ){
- sqlite3_free(pIter->pDoclist->a);
- sqlite3_free(pIter->pDoclist);
- }else{
- fts5MultiIterFree(pIter->pIndex, pIter->pMulti);
- fts5StructureRelease(pIter->pStruct);
- fts5BufferFree(&pIter->poslist);
- }
+ fts5MultiIterFree(pIter->pIndex, pIter->pMulti);
+ fts5StructureRelease(pIter->pStruct);
+ fts5BufferFree(&pIter->poslist);
fts5CloseReader(pIter->pIndex);
sqlite3_free(pIter);
}
dlidx.p = a;
dlidx.n = n;
- dlidx.nRef = 2;
memset(&lvl, 0, sizeof(Fts5DlidxLvl));
lvl.pData = &dlidx;