📄 fts1.c
字号:
return pReader->iLastPos;}/* Skip past the end of a position list. */static void skipPositionList(DocListReader *pReader){ 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'; return str;}/* Duplicate a string; the caller must free() the returned string. * (We don't use strdup() since it's not part of the standard C library and * may not be available everywhere.) */static char *string_dup(const char *s){ return string_dup_n(s, strlen(s));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -