📄 fts1.c
字号:
DocList *p = pReader->pDoclist;
if( p && p->iType>=DL_POSITIONS ){
int iColumn;
while( readPosition(pReader, &iColumn)!=-1 ){}
}
}
/* Skip over a docid, including its position list if the doclist has
* positions. */
static void skipDocument(DocListReader *pReader){
readDocid(pReader);
skipPositionList(pReader);
}
/* Skip past all docids which are less than [iDocid]. Returns 1 if a docid
* matching [iDocid] was found. */
static int skipToDocid(DocListReader *pReader, sqlite_int64 iDocid){
sqlite_int64 d = 0;
while( !atEnd(pReader) && (d=peekDocid(pReader))<iDocid ){
skipDocument(pReader);
}
return !atEnd(pReader) && d==iDocid;
}
/* Return the first document in a document list.
*/
static sqlite_int64 firstDocid(DocList *d){
DocListReader r;
readerInit(&r, d);
return readDocid(&r);
}
#ifdef SQLITE_DEBUG
/*
** This routine is used for debugging purpose only.
**
** Write the content of a doclist to standard output.
*/
static void printDoclist(DocList *p){
DocListReader r;
const char *zSep = "";
readerInit(&r, p);
while( !atEnd(&r) ){
sqlite_int64 docid = readDocid(&r);
if( docid==0 ){
skipPositionList(&r);
continue;
}
printf("%s%lld", zSep, docid);
zSep = ",";
if( p->iType>=DL_POSITIONS ){
int iPos, iCol;
const char *zDiv = "";
printf("(");
while( (iPos = readPosition(&r, &iCol))>=0 ){
printf("%s%d:%d", zDiv, iCol, iPos);
zDiv = ":";
}
printf(")");
}
}
printf("\n");
fflush(stdout);
}
#endif /* SQLITE_DEBUG */
/* Trim the given doclist to contain only positions in column
* [iRestrictColumn]. */
static void docListRestrictColumn(DocList *in, int iRestrictColumn){
DocListReader r;
DocList out;
assert( in->iType>=DL_POSITIONS );
readerInit(&r, in);
docListInit(&out, DL_POSITIONS, NULL, 0);
while( !atEnd(&r) ){
sqlite_int64 iDocid = readDocid(&r);
int iPos, iColumn;
docListAddDocid(&out, iDocid);
while( (iPos = readPosition(&r, &iColumn)) != -1 ){
if( iColumn==iRestrictColumn ){
docListAddPos(&out, iColumn, iPos);
}
}
}
docListDestroy(in);
*in = out;
}
/* Trim the given doclist by discarding any docids without any remaining
* positions. */
static void docListDiscardEmpty(DocList *in) {
DocListReader r;
DocList out;
/* TODO: It would be nice to implement this operation in place; that
* could save a significant amount of memory in queries with long doclists. */
assert( in->iType>=DL_POSITIONS );
readerInit(&r, in);
docListInit(&out, DL_POSITIONS, NULL, 0);
while( !atEnd(&r) ){
sqlite_int64 iDocid = readDocid(&r);
int match = 0;
int iPos, iColumn;
while( (iPos = readPosition(&r, &iColumn)) != -1 ){
if( !match ){
docListAddDocid(&out, iDocid);
match = 1;
}
docListAddPos(&out, iColumn, iPos);
}
}
docListDestroy(in);
*in = out;
}
/* Helper function for docListUpdate() and docListAccumulate().
** Splices a doclist element into the doclist represented by r,
** leaving r pointing after the newly spliced element.
*/
static void docListSpliceElement(DocListReader *r, sqlite_int64 iDocid,
const char *pSource, int nSource){
DocList *d = r->pDoclist;
char *pTarget;
int nTarget, found;
found = skipToDocid(r, iDocid);
/* Describe slice in d to place pSource/nSource. */
pTarget = r->p;
if( found ){
skipDocument(r);
nTarget = r->p-pTarget;
}else{
nTarget = 0;
}
/* The sense of the following is that there are three possibilities.
** If nTarget==nSource, we should not move any memory nor realloc.
** If nTarget>nSource, trim target and realloc.
** If nTarget<nSource, realloc then expand target.
*/
if( nTarget>nSource ){
memmove(pTarget+nSource, pTarget+nTarget, docListEnd(d)-(pTarget+nTarget));
}
if( nTarget!=nSource ){
int iDoclist = pTarget-d->pData;
d->pData = realloc(d->pData, d->nData+nSource-nTarget);
pTarget = d->pData+iDoclist;
}
if( nTarget<nSource ){
memmove(pTarget+nSource, pTarget+nTarget, docListEnd(d)-(pTarget+nTarget));
}
memcpy(pTarget, pSource, nSource);
d->nData += nSource-nTarget;
r->p = pTarget+nSource;
}
/* Insert/update pUpdate into the doclist. */
static void docListUpdate(DocList *d, DocList *pUpdate){
DocListReader reader;
assert( d!=NULL && pUpdate!=NULL );
assert( d->iType==pUpdate->iType);
readerInit(&reader, d);
docListSpliceElement(&reader, firstDocid(pUpdate),
pUpdate->pData, pUpdate->nData);
}
/* Propagate elements from pUpdate to pAcc, overwriting elements with
** matching docids.
*/
static void docListAccumulate(DocList *pAcc, DocList *pUpdate){
DocListReader accReader, updateReader;
/* Handle edge cases where one doclist is empty. */
assert( pAcc!=NULL );
if( pUpdate==NULL || pUpdate->nData==0 ) return;
if( pAcc->nData==0 ){
pAcc->pData = malloc(pUpdate->nData);
memcpy(pAcc->pData, pUpdate->pData, pUpdate->nData);
pAcc->nData = pUpdate->nData;
return;
}
readerInit(&accReader, pAcc);
readerInit(&updateReader, pUpdate);
while( !atEnd(&updateReader) ){
char *pSource = updateReader.p;
sqlite_int64 iDocid = readDocid(&updateReader);
skipPositionList(&updateReader);
docListSpliceElement(&accReader, iDocid, pSource, updateReader.p-pSource);
}
}
/*
** Read the next docid off of pIn. Return 0 if we reach the end.
*
* TODO: This assumes that docids are never 0, but they may actually be 0 since
* users can choose docids when inserting into a full-text table. Fix this.
*/
static sqlite_int64 nextDocid(DocListReader *pIn){
skipPositionList(pIn);
return atEnd(pIn) ? 0 : readDocid(pIn);
}
/*
** pLeft and pRight are two DocListReaders that are pointing to
** positions lists of the same document: iDocid.
**
** If there are no instances in pLeft or pRight where the position
** of pLeft is one less than the position of pRight, then this
** routine adds nothing to pOut.
**
** If there are one or more instances where positions from pLeft
** are exactly one less than positions from pRight, then add a new
** document record to pOut. If pOut wants to hold positions, then
** include the positions from pRight that are one more than a
** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1.
**
** pLeft and pRight are left pointing at the next document record.
*/
static void mergePosList(
DocListReader *pLeft, /* Left position list */
DocListReader *pRight, /* Right position list */
sqlite_int64 iDocid, /* The docid from pLeft and pRight */
DocList *pOut /* Write the merged document record here */
){
int iLeftCol, iLeftPos = readPosition(pLeft, &iLeftCol);
int iRightCol, iRightPos = readPosition(pRight, &iRightCol);
int match = 0;
/* Loop until we've reached the end of both position lists. */
while( iLeftPos!=-1 && iRightPos!=-1 ){
if( iLeftCol==iRightCol && iLeftPos+1==iRightPos ){
if( !match ){
docListAddDocid(pOut, iDocid);
match = 1;
}
if( pOut->iType>=DL_POSITIONS ){
docListAddPos(pOut, iRightCol, iRightPos);
}
iLeftPos = readPosition(pLeft, &iLeftCol);
iRightPos = readPosition(pRight, &iRightCol);
}else if( iRightCol<iLeftCol ||
(iRightCol==iLeftCol && iRightPos<iLeftPos+1) ){
iRightPos = readPosition(pRight, &iRightCol);
}else{
iLeftPos = readPosition(pLeft, &iLeftCol);
}
}
if( iLeftPos>=0 ) skipPositionList(pLeft);
if( iRightPos>=0 ) skipPositionList(pRight);
}
/* We have two doclists: pLeft and pRight.
** Write the phrase intersection of these two doclists into pOut.
**
** A phrase intersection means that two documents only match
** if pLeft.iPos+1==pRight.iPos.
**
** The output pOut may or may not contain positions. If pOut
** does contain positions, they are the positions of pRight.
*/
static void docListPhraseMerge(
DocList *pLeft, /* Doclist resulting from the words on the left */
DocList *pRight, /* Doclist for the next word to the right */
DocList *pOut /* Write the combined doclist here */
){
DocListReader left, right;
sqlite_int64 docidLeft, docidRight;
readerInit(&left, pLeft);
readerInit(&right, pRight);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
while( docidLeft>0 && docidRight>0 ){
if( docidLeft<docidRight ){
docidLeft = nextDocid(&left);
}else if( docidRight<docidLeft ){
docidRight = nextDocid(&right);
}else{
mergePosList(&left, &right, docidLeft, pOut);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
}
}
}
/* We have two doclists: pLeft and pRight.
** Write the intersection of these two doclists into pOut.
** Only docids are matched. Position information is ignored.
**
** The output pOut never holds positions.
*/
static void docListAndMerge(
DocList *pLeft, /* Doclist resulting from the words on the left */
DocList *pRight, /* Doclist for the next word to the right */
DocList *pOut /* Write the combined doclist here */
){
DocListReader left, right;
sqlite_int64 docidLeft, docidRight;
assert( pOut->iType<DL_POSITIONS );
readerInit(&left, pLeft);
readerInit(&right, pRight);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
while( docidLeft>0 && docidRight>0 ){
if( docidLeft<docidRight ){
docidLeft = nextDocid(&left);
}else if( docidRight<docidLeft ){
docidRight = nextDocid(&right);
}else{
docListAddDocid(pOut, docidLeft);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
}
}
}
/* We have two doclists: pLeft and pRight.
** Write the union of these two doclists into pOut.
** Only docids are matched. Position information is ignored.
**
** The output pOut never holds positions.
*/
static void docListOrMerge(
DocList *pLeft, /* Doclist resulting from the words on the left */
DocList *pRight, /* Doclist for the next word to the right */
DocList *pOut /* Write the combined doclist here */
){
DocListReader left, right;
sqlite_int64 docidLeft, docidRight, priorLeft;
readerInit(&left, pLeft);
readerInit(&right, pRight);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
while( docidLeft>0 && docidRight>0 ){
if( docidLeft<=docidRight ){
docListAddDocid(pOut, docidLeft);
}else{
docListAddDocid(pOut, docidRight);
}
priorLeft = docidLeft;
if( docidLeft<=docidRight ){
docidLeft = nextDocid(&left);
}
if( docidRight>0 && docidRight<=priorLeft ){
docidRight = nextDocid(&right);
}
}
while( docidLeft>0 ){
docListAddDocid(pOut, docidLeft);
docidLeft = nextDocid(&left);
}
while( docidRight>0 ){
docListAddDocid(pOut, docidRight);
docidRight = nextDocid(&right);
}
}
/* We have two doclists: pLeft and pRight.
** Write into pOut all documents that occur in pLeft but not
** in pRight.
**
** Only docids are matched. Position information is ignored.
**
** The output pOut never holds positions.
*/
static void docListExceptMerge(
DocList *pLeft, /* Doclist resulting from the words on the left */
DocList *pRight, /* Doclist for the next word to the right */
DocList *pOut /* Write the combined doclist here */
){
DocListReader left, right;
sqlite_int64 docidLeft, docidRight, priorLeft;
readerInit(&left, pLeft);
readerInit(&right, pRight);
docidLeft = nextDocid(&left);
docidRight = nextDocid(&right);
while( docidLeft>0 && docidRight>0 ){
priorLeft = docidLeft;
if( docidLeft<docidRight ){
docListAddDocid(pOut, docidLeft);
}
if( docidLeft<=docidRight ){
docidLeft = nextDocid(&left);
}
if( docidRight>0 && docidRight<=priorLeft ){
docidRight = nextDocid(&right);
}
}
while( docidLeft>0 ){
docListAddDocid(pOut, docidLeft);
docidLeft = nextDocid(&left);
}
}
static char *string_dup_n(const char *s, int n){
char *str = malloc(n + 1);
memcpy(str, s, n);
str[n] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -