/* Read the next docid. */ static sqlite_int64 readDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); pReader->p += getVarint(pReader->p, &ret); pReader->iLastPos = 0; return ret; }
/* Doclist multi-tool. Pass pUpdate==NULL to delete the indicated docid; * otherwise pUpdate, which must contain only the single docid [iDocid], is * inserted (if not present) or updated (if already present). */ static int docListUpdate(DocList *d, sqlite_int64 iDocid, DocList *pUpdate){ int modified = 0; DocListReader reader; char *p; if( pUpdate!=NULL ){ assert( d->iType==pUpdate->iType); assert( iDocid==firstDocid(pUpdate) ); } readerInit(&reader, d); while( !readerAtEnd(&reader) && peekDocid(&reader)<iDocid ){ skipDocument(&reader); } p = reader.p; /* Delete if there is a matching element. */ if( !readerAtEnd(&reader) && iDocid==peekDocid(&reader) ){ skipDocument(&reader); memmove(p, reader.p, docListEnd(d) - reader.p); d->nData -= (reader.p - p); modified = 1; } /* Insert if indicated. */ if( pUpdate!=NULL ){ int iDoclist = p-d->pData; docListAddEndPos(pUpdate); d->pData = realloc(d->pData, d->nData+pUpdate->nData); p = d->pData + iDoclist; memmove(p+pUpdate->nData, p, docListEnd(d) - p); memcpy(p, pUpdate->pData, pUpdate->nData); d->nData += pUpdate->nData; modified = 1; } return modified; }
/* Split the second half of doclist d into a separate doclist d2. Returns 1 * if successful, or 0 if d contains a single document and hence can't be * split. */ static int docListSplit(DocList *d, DocList *d2){ const char *pSplitPoint = d->pData + d->nData / 2; DocListReader reader; readerInit(&reader, d); while( reader.p<pSplitPoint ){ skipDocument(&reader); } if( readerAtEnd(&reader) ) return 0; docListInit(d2, d->iType, reader.p, docListEnd(d) - reader.p); d->nData = reader.p - d->pData; d->pData = realloc(d->pData, d->nData); return 1; }
/* Merge one block of an on-disk doclist into a DocListMerge. */ static void mergeBlock(DocListMerge *m, DocList *pBlock){ DocListReader blockReader; assert( pBlock->iType >= DL_POSITIONS ); readerInit(&blockReader, pBlock); while( !readerAtEnd(&blockReader) ){ sqlite_int64 iDocid = readDocid(&blockReader); if( m->in.pDoclist!=NULL ){ while( 1 ){ if( readerAtEnd(&m->in) ) return; /* nothing more to merge */ if( peekDocid(&m->in)>=iDocid ) break; skipDocument(&m->in); } if( peekDocid(&m->in)>iDocid ){ /* [pIn] has no match with iDocid */ skipPositionList(&blockReader); /* skip this docid in the block */ continue; } readDocid(&m->in); } /* We have a document match. */ if( m->in.pDoclist==NULL || m->in.pDoclist->iType < DL_POSITIONS ){ /* We don't need to do a poslist merge. */ docListAddDocid(m->pOut, iDocid); if( m->pOut->iType >= DL_POSITIONS ){ /* Copy all positions to the output doclist. */ while( 1 ){ int pos = readPosition(&blockReader); if( pos==-1 ) break; docListAddPos(m->pOut, pos); } docListAddEndPos(m->pOut); } else skipPositionList(&blockReader); continue; } mergePosList(m, iDocid, &blockReader); } }
static void mergeBlock(DocListMerge *m, DocList *pBlock){ DocListReader blockReader; assert( pBlock->iType >= DL_POSITIONS ); readerInit(&blockReader, pBlock); while( !readerAtEnd(&blockReader) ){ sqlite_int64 iDocid = readDocid(&blockReader); if( m->in.pDoclist!=NULL ){ while( 1 ){ if( readerAtEnd(&m->in) ) return; if( peekDocid(&m->in)>=iDocid ) break; skipDocument(&m->in); } if( peekDocid(&m->in)>iDocid ){ skipPositionList(&blockReader); continue; } readDocid(&m->in); } if( m->in.pDoclist==NULL || m->in.pDoclist->iType < DL_POSITIONS ){ docListAddDocid(m->pOut, iDocid); if( m->pOut->iType >= DL_POSITIONS ){ while( 1 ){ int pos = readPosition(&blockReader); if( pos==-1 ) break; docListAddPos(m->pOut, pos); } docListAddEndPos(m->pOut); } else skipPositionList(&blockReader); continue; } mergePosList(m, iDocid, &blockReader); } }
static int fulltextNext(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; sqlite_int64 iDocid; int rc; switch( c->iCursorType ){ case QUERY_GENERIC: /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); switch( rc ){ case SQLITE_ROW: c->eof = 0; return SQLITE_OK; case SQLITE_DONE: c->eof = 1; return SQLITE_OK; default: c->eof = 1; return rc; } case QUERY_FULLTEXT: rc = sqlite3_reset(c->pStmt); if( rc!=SQLITE_OK ) return rc; if( readerAtEnd(&c->result)){ c->eof = 1; return SQLITE_OK; } iDocid = readDocid(&c->result); rc = sqlite3_bind_int64(c->pStmt, 1, iDocid); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); if( rc==SQLITE_ROW ){ /* the case we expect */ c->eof = 0; return SQLITE_OK; } /* an error occurred; abort */ return rc==SQLITE_DONE ? SQLITE_ERROR : rc; default: assert( 0 ); return SQLITE_ERROR; /* not reached */ } }
static int fulltextNext(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; sqlite_int64 iDocid; int rc; switch( c->iCursorType ){ case QUERY_GENERIC: rc = sqlite3_step(c->pStmt); switch( rc ){ case SQLITE_ROW: c->eof = 0; return SQLITE_OK; case SQLITE_DONE: c->eof = 1; return SQLITE_OK; default: c->eof = 1; return rc; } case QUERY_FULLTEXT: rc = sqlite3_reset(c->pStmt); if( rc!=SQLITE_OK ) return rc; if( readerAtEnd(&c->result)){ c->eof = 1; return SQLITE_OK; } iDocid = readDocid(&c->result); rc = sqlite3_bind_int64(c->pStmt, 1, iDocid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(c->pStmt); if( rc==SQLITE_ROW ){ c->eof = 0; return SQLITE_OK; } return rc==SQLITE_DONE ? SQLITE_ERROR : rc; default: assert( 0 ); return SQLITE_ERROR; } }
/* Read the next position from a position list. * Returns the position, or -1 at the end of the list. */ static int readPosition(DocListReader *pReader){ int i; int iType = pReader->pDoclist->iType; assert( iType>=DL_POSITIONS ); assert( !readerAtEnd(pReader) ); pReader->p += getVarint32(pReader->p, &i); if( i==0 ){ pReader->iLastPos = -1; return -1; } pReader->iLastPos += ((int) i)-1; if( iType>=DL_POSITIONS_OFFSETS ){ /* Skip over offsets, ignoring them for now. */ int iStart, iEnd; pReader->p += getVarint32(pReader->p, &iStart); pReader->p += getVarint32(pReader->p, &iEnd); } return pReader->iLastPos; }
/* Peek at the next docid without advancing the read pointer. */ static sqlite_int64 peekDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); getVarint(pReader->p, &ret); return ret; }