Index: ext/fts5/fts5.c ================================================================== --- ext/fts5/fts5.c +++ ext/fts5/fts5.c @@ -503,11 +503,11 @@ return rc; } static int fts5StmtType(int idxNum){ if( FTS5_PLAN(idxNum)==FTS5_PLAN_SCAN ){ - return (idxNum&FTS5_ORDER_ASC) ? FTS5_STMT_SCAN_ASC : FTS5_STMT_SCAN_DESC; + return (idxNum&FTS5_ORDER_DESC) ? FTS5_STMT_SCAN_DESC : FTS5_STMT_SCAN_ASC; } return FTS5_STMT_LOOKUP; } /* @@ -650,11 +650,11 @@ } return rc; } -static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bAsc){ +static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ Fts5Config *pConfig = pTab->pConfig; Fts5Sorter *pSorter; int nPhrase; int nByte; int rc = SQLITE_OK; @@ -678,11 +678,11 @@ ** If SQLite a built-in statement cache, this wouldn't be a problem. */ zSql = sqlite3_mprintf("SELECT rowid, rank FROM %Q.%Q ORDER BY %s(%s%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), (zRankArgs ? zRankArgs : ""), - bAsc ? "ASC" : "DESC" + bDesc ? "DESC" : "ASC" ); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pSorter->pStmt, 0); @@ -704,13 +704,13 @@ } return rc; } -static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bAsc){ +static int fts5CursorFirst(Fts5Table *pTab, Fts5Cursor *pCsr, int bDesc){ int rc; - rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, bAsc); + rc = sqlite3Fts5ExprFirst(pCsr->pExpr, pTab->pIndex, bDesc); if( sqlite3Fts5ExprEof(pCsr->pExpr) ){ CsrFlagSet(pCsr, FTS5CSR_EOF); } fts5CsrNewrow(pCsr); return rc; @@ -871,11 +871,11 @@ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ Fts5Table *pTab = (Fts5Table*)(pCursor->pVtab); Fts5Cursor *pCsr = (Fts5Cursor*)pCursor; - int bAsc = ((idxNum & FTS5_ORDER_ASC) ? 1 : 0); + int bDesc = ((idxNum & FTS5_ORDER_DESC) ? 1 : 0); int rc = SQLITE_OK; assert( nVal<=2 ); assert( pCsr->pStmt==0 ); assert( pCsr->pExpr==0 ); @@ -892,11 +892,11 @@ ** (pCursor) is used to execute the query issued by function ** fts5CursorFirstSorted() above. */ assert( FTS5_PLAN(idxNum)==FTS5_PLAN_SCAN ); pCsr->idxNum = FTS5_PLAN_SOURCE; pCsr->pExpr = pTab->pSortCsr->pExpr; - rc = fts5CursorFirst(pTab, pCsr, bAsc); + rc = fts5CursorFirst(pTab, pCsr, bDesc); }else{ int ePlan = FTS5_PLAN(idxNum); pCsr->idxNum = idxNum; if( ePlan==FTS5_PLAN_MATCH || ePlan==FTS5_PLAN_SORTED_MATCH ){ const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); @@ -911,13 +911,13 @@ }else{ char **pzErr = &pTab->base.zErrMsg; rc = sqlite3Fts5ExprNew(pTab->pConfig, zExpr, &pCsr->pExpr, pzErr); if( rc==SQLITE_OK ){ if( ePlan==FTS5_PLAN_MATCH ){ - rc = fts5CursorFirst(pTab, pCsr, bAsc); + rc = fts5CursorFirst(pTab, pCsr, bDesc); }else{ - rc = fts5CursorFirstSorted(pTab, pCsr, bAsc); + rc = fts5CursorFirstSorted(pTab, pCsr, bDesc); } } } } }else{ Index: ext/fts5/fts5Int.h ================================================================== --- ext/fts5/fts5Int.h +++ ext/fts5/fts5Int.h @@ -227,11 +227,11 @@ /* ** Values used as part of the flags argument passed to IndexQuery(). */ #define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ -#define FTS5INDEX_QUERY_ASC 0x0002 /* Docs in ascending rowid order */ +#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */ /* ** Create/destroy an Fts5Index object. */ int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); @@ -363,10 +363,17 @@ /************************************************************************** ** Interface to code in fts5_hash.c. */ typedef struct Fts5Hash Fts5Hash; +typedef struct Fts5Data Fts5Data; +struct Fts5Data { + u8 *p; /* Pointer to buffer containing record */ + int n; /* Size of record in bytes */ + int nRef; /* Ref count */ +}; + /* ** Create a hash table, free a hash table. */ int sqlite3Fts5HashNew(Fts5Hash**, int *pnSize); void sqlite3Fts5HashFree(Fts5Hash*); @@ -393,10 +400,15 @@ int (*xTerm)(void*, const char*, int), int (*xEntry)(void*, i64, const u8*, int), int (*xTermDone)(void*) ); +int sqlite3Fts5HashQuery( + Fts5Hash*, /* Hash table to query */ + const char *pTerm, int nTerm, /* Query term */ + Fts5Data **ppData /* OUT: Query result */ +); /* ** End of interface to code in fts5_hash.c. **************************************************************************/ @@ -468,19 +480,19 @@ Fts5Expr **ppNew, char **pzErr ); /* -** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bAsc); +** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc); ** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr); ** rc = sqlite3Fts5ExprNext(pExpr) ** ){ ** // The document with rowid iRowid matches the expression! ** i64 iRowid = sqlite3Fts5ExprRowid(pExpr); ** } */ -int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, int bAsc); +int sqlite3Fts5ExprFirst(Fts5Expr*, Fts5Index *pIdx, int bDesc); int sqlite3Fts5ExprNext(Fts5Expr*); int sqlite3Fts5ExprEof(Fts5Expr*); i64 sqlite3Fts5ExprRowid(Fts5Expr*); void sqlite3Fts5ExprFree(Fts5Expr*); Index: ext/fts5/fts5_expr.c ================================================================== --- ext/fts5/fts5_expr.c +++ ext/fts5/fts5_expr.c @@ -30,11 +30,11 @@ void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*); struct Fts5Expr { Fts5Index *pIndex; Fts5ExprNode *pRoot; - int bAsc; + int bDesc; /* Iterate in descending docid order */ int nPhrase; /* Number of phrases in expression */ Fts5ExprPhrase **apExprPhrase; /* Pointers to phrase objects */ }; /* @@ -598,37 +598,37 @@ return SQLITE_OK; } /* -** Advance iterator pIter until it points to a value equal to or smaller -** than the initial value of *piMin. If this means the iterator points -** to a value smaller than *piMin, update *piMin to the new smallest value. +** Advance iterator pIter until it points to a value equal to or laster +** than the initial value of *piLast. If this means the iterator points +** to a value laster than *piLast, update *piLast to the new lastest value. ** ** If the iterator reaches EOF, set *pbEof to true before returning. If ** an error occurs, set *pRc to an error code. If either *pbEof or *pRc ** are set, return a non-zero value. Otherwise, return zero. */ static int fts5ExprAdvanceto( Fts5IndexIter *pIter, /* Iterator to advance */ - int bAsc, /* True if iterator is "rowid ASC" */ + int bDesc, /* True if iterator is "rowid DESC" */ i64 *piLast, /* IN/OUT: Lastest rowid seen so far */ int *pRc, /* OUT: Error code */ int *pbEof /* OUT: Set to true if EOF */ ){ i64 iLast = *piLast; i64 iRowid; iRowid = sqlite3Fts5IterRowid(pIter); - if( (bAsc==0 && iRowid>iLast) || (bAsc && iRowidiRowid) || (bDesc && iLast=iLast) ); + assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) ); } *piLast = iRowid; return 0; } @@ -654,16 +654,17 @@ int rc = SQLITE_OK; int i, j; /* Phrase and token index, respectively */ i64 iLast; /* Lastest rowid any iterator points to */ int bMatch; /* True if all terms are at the same rowid */ - /* Set iLast, the lastest rowid any iterator points to. If the iterator - ** skips through rowids in the default descending order, this means the - ** minimum rowid. Or, if the iterator is "ORDER BY rowid ASC", then it - ** means the maximum rowid. */ + /* Initialize iLast, the "lastest" rowid any iterator points to. If the + ** iterator skips through rowids in the default ascending order, this means + ** the maximum rowid. Or, if the iterator is "ORDER BY rowid DESC", then it + ** means the minimum rowid. */ iLast = sqlite3Fts5IterRowid(pNear->apPhrase[0]->aTerm[0].pIter); - if( bFromValid && (iFrom>iLast)==(pExpr->bAsc!=0) ){ + if( bFromValid && (iFrom>iLast)==(pExpr->bDesc==0) ){ + assert( pExpr->bDesc || iFrom>=iLast ); iLast = iFrom; } do { bMatch = 1; @@ -671,11 +672,11 @@ Fts5ExprPhrase *pPhrase = pNear->apPhrase[i]; for(j=0; jnTerm; j++){ Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; i64 iRowid = sqlite3Fts5IterRowid(pIter); if( iRowid!=iLast ) bMatch = 0; - if( fts5ExprAdvanceto(pIter, pExpr->bAsc, &iLast, &rc, &pNode->bEof) ){ + if( fts5ExprAdvanceto(pIter, pExpr->bDesc, &iLast, &rc, &pNode->bEof) ){ return rc; } } } }while( bMatch==0 ); @@ -772,11 +773,11 @@ for(j=0; jnTerm; j++){ pTerm = &pPhrase->aTerm[j]; rc = sqlite3Fts5IndexQuery( pExpr->pIndex, pTerm->zTerm, strlen(pTerm->zTerm), (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) | - (pExpr->bAsc ? FTS5INDEX_QUERY_ASC : 0), + (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0), &pTerm->pIter ); assert( rc==SQLITE_OK || pTerm->pIter==0 ); if( pTerm->pIter==0 || sqlite3Fts5IterEof(pTerm->pIter) ){ pNode->bEof = 1; @@ -808,11 +809,11 @@ Fts5ExprNode *p1, Fts5ExprNode *p2 ){ if( p2->bEof ) return -1; if( p1->bEof ) return +1; - if( pExpr->bAsc ){ + if( pExpr->bDesc==0 ){ if( p1->iRowidiRowid ) return -1; return (p1->iRowid > p2->iRowid); }else{ if( p1->iRowid>p2->iRowid ) return -1; return (p1->iRowid < p2->iRowid); @@ -909,22 +910,21 @@ case FTS5_AND: { Fts5ExprNode *p1 = pNode->pLeft; Fts5ExprNode *p2 = pNode->pRight; - while( p1->bEof==0 && p2->bEof==0 && p2->iRowid!=p1->iRowid ){ Fts5ExprNode *pAdv; - assert( pExpr->bAsc==0 || pExpr->bAsc==1 ); - if( pExpr->bAsc==(p1->iRowid < p2->iRowid) ){ + assert( pExpr->bDesc==0 || pExpr->bDesc==1 ); + if( pExpr->bDesc==(p1->iRowid > p2->iRowid) ){ pAdv = p1; - if( bFromValid==0 || pExpr->bAsc==(p2->iRowid > iFrom) ){ + if( bFromValid==0 || pExpr->bDesc==(p2->iRowid < iFrom) ){ iFrom = p2->iRowid; } }else{ pAdv = p2; - if( bFromValid==0 || pExpr->bAsc==(p1->iRowid > iFrom) ){ + if( bFromValid==0 || pExpr->bDesc==(p1->iRowid < iFrom) ){ iFrom = p1->iRowid; } } rc = fts5ExprNodeNext(pExpr, pAdv, 1, iFrom); if( rc!=SQLITE_OK ) break; @@ -1001,22 +1001,22 @@ /* ** Begin iterating through the set of documents in index pIdx matched by -** the MATCH expression passed as the first argument. If the "bAsc" parameter -** is passed a non-zero value, iteration is in ascending rowid order. Or, -** if it is zero, in descending order. +** the MATCH expression passed as the first argument. If the "bDesc" parameter +** is passed a non-zero value, iteration is in descending rowid order. Or, +** if it is zero, in ascending order. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. It ** is not considered an error if the query does not match any documents. */ -int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, int bAsc){ +int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, int bDesc){ int rc = SQLITE_OK; if( p->pRoot ){ p->pIndex = pIdx; - p->bAsc = bAsc; + p->bDesc = bDesc; rc = fts5ExprNodeFirst(p, p->pRoot); } return rc; } Index: ext/fts5/fts5_hash.c ================================================================== --- ext/fts5/fts5_hash.c +++ ext/fts5/fts5_hash.c @@ -53,19 +53,29 @@ */ struct Fts5HashEntry { Fts5HashEntry *pNext; /* Next hash entry with same hash-key */ int nAlloc; /* Total size of allocation */ - int iRowidOff; /* Offset of last rowid written */ + int iSzPoslist; /* Offset of space for 4-byte poslist size */ int nData; /* Total bytes of data (incl. structure) */ int iCol; /* Column of last value written */ int iPos; /* Position of last value written */ i64 iRowid; /* Rowid of last value written */ char zKey[0]; /* Nul-terminated entry key */ }; +/* +** Format value iVal as a 4-byte varint and write it to buffer a[]. 4 bytes +** are used even if the value could fit in a smaller amount of space. +*/ +static void fts5Put4ByteVarint(u8 *a, int iVal){ + a[0] = (0x80 | (u8)(iVal >> 21)); + a[1] = (0x80 | (u8)(iVal >> 14)); + a[2] = (0x80 | (u8)(iVal >> 7)); + a[3] = (0x7F & (u8)(iVal)); +} /* ** Allocate a new hash table. */ int sqlite3Fts5HashNew(Fts5Hash **ppNew, int *pnByte){ @@ -159,29 +169,10 @@ pHash->nSlot = nNew; pHash->aSlot = apNew; return SQLITE_OK; } -/* -** Store the 32-bit integer passed as the second argument in buffer p. -*/ -static int fts5PutNativeInt(u8 *p, int i){ - assert( sizeof(i)==4 ); - memcpy(p, &i, sizeof(i)); - return sizeof(i); -} - -/* -** Read and return the 32-bit integer stored in buffer p. -*/ -static int fts5GetNativeU32(u8 *p){ - int i; - assert( sizeof(i)==4 ); - memcpy(&i, p, sizeof(i)); - return i; -} - int sqlite3Fts5HashWrite( Fts5Hash *pHash, i64 iRowid, /* Rowid for this entry */ int iCol, /* Column token appears in (-ve -> delete) */ int iPos, /* Position of token within column */ @@ -190,11 +181,11 @@ unsigned int iHash = fts5HashKey(pHash->nSlot, pToken, nToken); Fts5HashEntry *p; u8 *pPtr; int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */ - /* Attempt to locate an existing hash object */ + /* Attempt to locate an existing hash entry */ for(p=pHash->aSlot[iHash]; p; p=p->pNext){ if( memcmp(p->zKey, pToken, nToken)==0 && p->zKey[nToken]==0 ) break; } /* If an existing hash entry cannot be found, create a new one. */ @@ -212,30 +203,31 @@ if( !p ) return SQLITE_NOMEM; memset(p, 0, sizeof(Fts5HashEntry)); p->nAlloc = nByte; memcpy(p->zKey, pToken, nToken); p->zKey[nToken] = '\0'; - p->iRowidOff = p->nData = nToken + 1 + sizeof(Fts5HashEntry); + p->nData = nToken + 1 + sizeof(Fts5HashEntry); p->nData += sqlite3PutVarint(&((u8*)p)[p->nData], iRowid); + p->iSzPoslist = p->nData; + p->nData += 4; p->iRowid = iRowid; p->pNext = pHash->aSlot[iHash]; pHash->aSlot[iHash] = p; pHash->nEntry++; - nIncr += p->nData; } /* Check there is enough space to append a new entry. Worst case scenario ** is: ** - ** + 4 bytes for the previous entry size field, ** + 9 bytes for a new rowid, + ** + 4 bytes reserved for the "poslist size" varint. ** + 1 byte for a "new column" byte, ** + 3 bytes for a new column number (16-bit max) as a varint, ** + 5 bytes for the new position offset (32-bit max). */ - if( (p->nAlloc - p->nData) < (4 + 9 + 1 + 3 + 5) ){ + if( (p->nAlloc - p->nData) < (9 + 4 + 1 + 3 + 5) ){ int nNew = p->nAlloc * 2; Fts5HashEntry *pNew; Fts5HashEntry **pp; pNew = (Fts5HashEntry*)sqlite3_realloc(p, nNew); if( pNew==0 ) return SQLITE_NOMEM; @@ -248,13 +240,15 @@ nIncr -= p->nData; /* If this is a new rowid, append the 4-byte size field for the previous ** entry, and the new rowid for this entry. */ if( iRowid!=p->iRowid ){ - p->nData += fts5PutNativeInt(&pPtr[p->nData], p->nData - p->iRowidOff); - p->iRowidOff = p->nData; - p->nData += sqlite3PutVarint(&pPtr[p->nData], iRowid); + assert( p->iSzPoslist>0 ); + fts5Put4ByteVarint(&pPtr[p->iSzPoslist], p->nData - p->iSzPoslist - 4); + p->nData += sqlite3PutVarint(&pPtr[p->nData], iRowid - p->iRowid); + p->iSzPoslist = p->nData; + p->nData += 4; p->iCol = 0; p->iPos = 0; p->iRowid = iRowid; } @@ -377,37 +371,38 @@ rc = fts5HashEntrySort(pHash, &pList); if( rc==SQLITE_OK ){ while( pList ){ Fts5HashEntry *pNext = pList->pNext; if( rc==SQLITE_OK ){ + const int nSz = pList->nData - pList->iSzPoslist - 4; + const int nKey = strlen(pList->zKey); + i64 iRowid = 0; u8 *pPtr = (u8*)pList; - int nKey = strlen(pList->zKey); - int iOff = pList->iRowidOff; - int iEnd = sizeof(Fts5HashEntry) + nKey + 1; - int nByte = pList->nData - pList->iRowidOff; + int iOff = sizeof(Fts5HashEntry) + nKey + 1; + /* Fill in the final poslist size field */ + fts5Put4ByteVarint(&pPtr[pList->iSzPoslist], nSz); + + /* Issue the new-term callback */ rc = xTerm(pCtx, pList->zKey, nKey); - while( rc==SQLITE_OK && iOff ){ - int nVarint; - i64 iRowid; - nVarint = getVarint(&pPtr[iOff], (u64*)&iRowid); - rc = xEntry(pCtx, iRowid, &pPtr[iOff+nVarint], nByte-nVarint); - if( iOff==iEnd ){ - iOff = 0; - }else{ - nByte = fts5GetNativeU32(&pPtr[iOff-sizeof(int)]); - iOff = iOff - sizeof(int) - nByte; - } - } - if( rc==SQLITE_OK ){ - rc = xTermDone(pCtx); - } + + /* Issue the xEntry callbacks */ + while( rc==SQLITE_OK && iOffnData ){ + i64 iDelta; /* Rowid delta value */ + int nPoslist; /* Size of position list in bytes */ + iOff += getVarint(&pPtr[iOff], (u64*)&iDelta); + iRowid += iDelta; + iOff += fts5GetVarint32(&pPtr[iOff], nPoslist); + rc = xEntry(pCtx, iRowid, &pPtr[iOff], nPoslist); + iOff += nPoslist; + } + + /* Issue the term-done callback */ + if( rc==SQLITE_OK ) rc = xTermDone(pCtx); } sqlite3_free(pList); pList = pNext; } } return rc; } - - Index: ext/fts5/fts5_index.c ================================================================== --- ext/fts5/fts5_index.c +++ ext/fts5/fts5_index.c @@ -42,11 +42,11 @@ */ #define FTS5_OPT_WORK_UNIT 1000 /* Number of leaf pages per optimize step */ #define FTS5_WORK_UNIT 64 /* Number of leaf pages in unit of work */ -#define FTS5_MIN_DLIDX_SIZE 4 /* Add dlidx if this many empty pages */ +#define FTS5_MIN_DLIDX_SIZE 4000 /* Add dlidx if this many empty pages */ /* ** Details: ** ** The %_data table managed by this module, @@ -268,11 +268,10 @@ #define FTS5_DATA_ZERO_PADDING 8 typedef struct Fts5BtreeIter Fts5BtreeIter; typedef struct Fts5BtreeIterLevel Fts5BtreeIterLevel; typedef struct Fts5ChunkIter Fts5ChunkIter; -typedef struct Fts5Data Fts5Data; typedef struct Fts5DlidxIter Fts5DlidxIter; typedef struct Fts5MultiSegIter Fts5MultiSegIter; typedef struct Fts5NodeIter Fts5NodeIter; typedef struct Fts5PageWriter Fts5PageWriter; typedef struct Fts5PosIter Fts5PosIter; @@ -309,11 +308,11 @@ sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ int nRead; /* Total number of blocks read */ }; struct Fts5DoclistIter { - int bAsc; + int bDesc; /* True for DESC order, false for ASC */ u8 *a; int n; int i; /* Output variables. aPoslist==0 at EOF */ @@ -331,19 +330,10 @@ Fts5MultiSegIter *pMulti; Fts5DoclistIter *pDoclist; Fts5Buffer poslist; /* Buffer containing current poslist */ }; -/* -** A single record read from the %_data table. -*/ -struct Fts5Data { - u8 *p; /* Pointer to buffer containing record */ - int n; /* Size of record in bytes */ - int nRef; /* Ref count */ -}; - /* ** The contents of the "structure" record for each index are represented ** using an Fts5Structure record in memory. Which uses instances of the ** other Fts5StructureXXX types as components. */ @@ -1480,10 +1470,15 @@ if( pIter ){ fts5DataRelease(pIter->pData); sqlite3_free(pIter); } } + +static void fts5LeafHeader(Fts5Data *pLeaf, int *piRowid, int *piTerm){ + *piRowid = (int)fts5GetU16(&pLeaf->p[0]); + *piTerm = (int)fts5GetU16(&pLeaf->p[2]); +} /* ** Load the next leaf page into the segment iterator. */ static void fts5SegIterNextPage( @@ -1501,12 +1496,19 @@ pIter->pLeaf = 0; } } /* -** Leave pIter->iLeafOffset as the offset to the size field of the first -** position list. The position list belonging to document pIter->iRowid. +** Fts5SegIter.iLeafOffset currently points to the first byte of the +** "nSuffix" field of a term. Function parameter nKeep contains the value +** of the "nPrefix" field (if there was one - it is passed 0 if this is +** the first term in the segment). +** +** This function populates (Fts5SegIter.term) and (Fts5SegIter.iRowid) +** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the offset to +** the size field of the first position list. The position list belonging +** to document (Fts5SegIter.iRowid). */ static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ int iOff = pIter->iLeafOffset; /* Offset to read at */ int nNew; /* Bytes of new data */ @@ -1567,15 +1569,10 @@ pIter->iLeafOffset = fts5GetU16(&a[2]); fts5SegIterLoadTerm(p, pIter, 0); } } -static void fts5LeafHeader(Fts5Data *pLeaf, int *piRowid, int *piTerm){ - *piRowid = (int)fts5GetU16(&pLeaf->p[0]); - *piTerm = (int)fts5GetU16(&pLeaf->p[2]); -} - /* ** This function is only ever called on iterators created by calls to ** Fts5IndexQuery() with the FTS5INDEX_QUERY_ASC flag set. ** ** When this function is called, iterator pIter points to the first rowid @@ -1596,11 +1593,11 @@ i += fts5GetVarint32(&a[i], nPos); i += nPos; if( i>=n ) break; i += getVarint(&a[i], (u64*)&iDelta); if( iDelta==0 ) break; - pIter->iRowid -= iDelta; + pIter->iRowid += iDelta; if( iRowidOffset>=pIter->nRowidOffset ){ int nNew = pIter->nRowidOffset + 8; int *aNew = (int*)sqlite3_realloc(pIter->aRowidOffset, nNew*sizeof(int)); if( aNew==0 ){ @@ -1676,11 +1673,11 @@ if( p->rc==SQLITE_OK && pLeaf ){ if( pIter->iLeafOffsetn ){ bRet = (pLeaf->p[pIter->iLeafOffset]==0x00); }else{ Fts5Data *pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID( - pIter->iIdx, pIter->pSeg->iSegid, 0, pIter->iLeafPgno + pIter->iIdx, pIter->pSeg->iSegid, 0, pIter->iLeafPgno+1 )); if( pNew ){ bRet = (pNew->p[4]==0x00); fts5DataRelease(pNew); } @@ -1711,11 +1708,11 @@ pIter->iLeafOffset = iOff = pIter->aRowidOffset[pIter->iRowidOffset]; iOff += fts5GetVarint32(&a[iOff], nPos); iOff += nPos; getVarint(&a[iOff], (u64*)&iDelta); - pIter->iRowid += iDelta; + pIter->iRowid -= iDelta; }else{ fts5SegIterReverseNewPage(p, pIter); } }else{ Fts5Data *pLeaf = pIter->pLeaf; @@ -1746,11 +1743,11 @@ pIter->iLeafOffset = 4; }else if( iOff!=fts5GetU16(&a[2]) ){ pIter->iLeafOffset += fts5GetVarint32(&a[iOff], nKeep); } }else{ - pIter->iRowid -= iDelta; + pIter->iRowid += iDelta; } }else{ iOff = 0; /* Next entry is not on the current page */ while( iOff==0 ){ @@ -1920,11 +1917,11 @@ int iPg = 1; int h; int bGe = ((flags & FTS5INDEX_QUERY_PREFIX) && iIdx==0); int bDlidx = 0; /* True if there is a doclist-index */ - assert( bGe==0 || (flags & FTS5INDEX_QUERY_ASC)==0 ); + assert( bGe==0 || (flags & FTS5INDEX_QUERY_DESC)==0 ); assert( pTerm && nTerm ); memset(pIter, 0, sizeof(*pIter)); pIter->pSeg = pSeg; pIter->iIdx = iIdx; @@ -1978,17 +1975,17 @@ } if( p->rc==SQLITE_OK && bGe==0 ){ pIter->flags |= FTS5_SEGITER_ONETERM; if( pIter->pLeaf ){ - if( flags & FTS5INDEX_QUERY_ASC ){ + if( flags & FTS5INDEX_QUERY_DESC ){ pIter->flags |= FTS5_SEGITER_REVERSE; } if( bDlidx ){ fts5SegIterLoadDlidx(p, iIdx, pIter); } - if( flags & FTS5INDEX_QUERY_ASC ){ + if( flags & FTS5INDEX_QUERY_DESC ){ fts5SegIterReverse(p, iIdx, pIter); } } } } @@ -2040,11 +2037,11 @@ int res = fts5BufferCompare(&p1->term, &p2->term); if( res==0 ){ assert( i2>i1 ); assert( i2!=0 ); if( p1->iRowid==p2->iRowid ) return i2; - res = ((p1->iRowid < p2->iRowid)==pIter->bRev) ? -1 : +1; + res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1; } assert( res!=0 ); if( res<0 ){ iRes = i1; }else{ @@ -2054,39 +2051,10 @@ pIter->aFirst[iOut] = iRes; return 0; } -/* -** Free the iterator object passed as the second argument. -*/ -static void fts5MultiIterFree(Fts5Index *p, Fts5MultiSegIter *pIter){ - if( pIter ){ - int i; - for(i=0; inSeg; i++){ - fts5SegIterClear(&pIter->aSeg[i]); - } - sqlite3_free(pIter); - } -} - -static void fts5MultiIterAdvanced( - Fts5Index *p, /* FTS5 backend to iterate within */ - Fts5MultiSegIter *pIter, /* Iterator to update aFirst[] array for */ - int iChanged, /* Index of sub-iterator just advanced */ - int iMinset /* Minimum entry in aFirst[] to set */ -){ - int i; - for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ - int iEq; - if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ - fts5SegIterNext(p, &pIter->aSeg[iEq]); - i = pIter->nSeg + iEq; - } - } -} - /* ** Move the seg-iter so that it points to the first rowid on page iLeafPgno. ** It is an error if leaf iLeafPgno contains no rowid. */ static void fts5SegIterGotoPage( @@ -2168,10 +2136,40 @@ if( bRev!=0 && pIter->iRowid>=iMatch ) break; bMove = 1; } } + +/* +** Free the iterator object passed as the second argument. +*/ +static void fts5MultiIterFree(Fts5Index *p, Fts5MultiSegIter *pIter){ + if( pIter ){ + int i; + for(i=0; inSeg; i++){ + fts5SegIterClear(&pIter->aSeg[i]); + } + sqlite3_free(pIter); + } +} + +static void fts5MultiIterAdvanced( + Fts5Index *p, /* FTS5 backend to iterate within */ + Fts5MultiSegIter *pIter, /* Iterator to update aFirst[] array for */ + int iChanged, /* Index of sub-iterator just advanced */ + int iMinset /* Minimum entry in aFirst[] to set */ +){ + int i; + for(i=(pIter->nSeg+iChanged)/2; i>=iMinset && p->rc==SQLITE_OK; i=i/2){ + int iEq; + if( (iEq = fts5MultiIterDoCompare(pIter, i)) ){ + fts5SegIterNext(p, &pIter->aSeg[iEq]); + i = pIter->nSeg + iEq; + } + } +} + /* ** Move the iterator to the next entry. ** ** If an error occurs, an error code is left in Fts5Index.rc. It is not ** considered an error if the iterator reaches EOF, or if it is already at @@ -2246,11 +2244,11 @@ ); if( pNew==0 ) return; pNew->nSeg = nSlot; pNew->aSeg = (Fts5SegIter*)&pNew[1]; pNew->aFirst = (u16*)&pNew->aSeg[nSlot]; - pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_ASC)); + pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC)); pNew->bSkipEmpty = bSkipEmpty; /* Initialize each of the component segment iterators. */ if( iLevel<0 ){ Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel]; @@ -2326,12 +2324,12 @@ while( 1 ){ i64 iRowid; fts5MultiIterNext(p, pIter, 1, iMatch); if( fts5MultiIterEof(p, pIter) ) break; iRowid = fts5MultiIterRowid(pIter); - if( pIter->bRev==0 && iRowid<=iMatch ) break; - if( pIter->bRev!=0 && iRowid>=iMatch ) break; + if( pIter->bRev==0 && iRowid>=iMatch ) break; + if( pIter->bRev!=0 && iRowid<=iMatch ) break; } } /* ** Return a pointer to a buffer containing the term associated with the @@ -2792,12 +2790,12 @@ /* Write the docid. */ if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ - assert( p->rc || iRowidiPrevRowid ); - fts5BufferAppendVarint(&p->rc, &pPage->buf, pWriter->iPrevRowid - iRowid); + assert( p->rc || iRowid>pWriter->iPrevRowid ); + fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid); } pWriter->iPrevRowid = iRowid; pWriter->bFirstRowidInDoclist = 0; pWriter->bFirstRowidInPage = 0; @@ -3709,14 +3707,14 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){ if( pIter->in ){ if( pIter->i ){ i64 iDelta; pIter->i += getVarint(&pIter->a[pIter->i], (u64*)&iDelta); - if( pIter->bAsc ){ - pIter->iRowid += iDelta; - }else{ + if( pIter->bDesc ){ pIter->iRowid -= iDelta; + }else{ + pIter->iRowid += iDelta; } }else{ pIter->i += getVarint(&pIter->a[pIter->i], (u64*)&pIter->iRowid); } pIter->i += fts5GetVarint32(&pIter->a[pIter->i], pIter->nPoslist); @@ -3727,33 +3725,33 @@ } } static void fts5DoclistIterInit( Fts5Buffer *pBuf, - int bAsc, + int bDesc, Fts5DoclistIter *pIter ){ memset(pIter, 0, sizeof(*pIter)); pIter->a = pBuf->p; pIter->n = pBuf->n; - pIter->bAsc = bAsc; + pIter->bDesc = bDesc; fts5DoclistIterNext(pIter); } /* ** Append a doclist to buffer pBuf. */ static void fts5MergeAppendDocid( int *pRc, /* IN/OUT: Error code */ - int bAsc, + 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( bAsc==0 ){ + }else if( bDesc ){ fts5BufferAppendVarint(pRc, pBuf, *piLastRowid - iRowid); }else{ fts5BufferAppendVarint(pRc, pBuf, iRowid - *piLastRowid); } *piLastRowid = iRowid; @@ -3767,11 +3765,11 @@ ** If an error occurs, an error code is left in p->rc. If an error has ** already occurred, this function is a no-op. */ static void fts5MergePrefixLists( Fts5Index *p, /* FTS5 backend object */ - int bAsc, + int bDesc, Fts5Buffer *p1, /* First list to merge */ Fts5Buffer *p2 /* Second list to merge */ ){ if( p2->n ){ i64 iLastRowid = 0; @@ -3780,25 +3778,25 @@ Fts5Buffer out; Fts5Buffer tmp; memset(&out, 0, sizeof(out)); memset(&tmp, 0, sizeof(tmp)); - fts5DoclistIterInit(p1, bAsc, &i1); - fts5DoclistIterInit(p2, bAsc, &i2); + fts5DoclistIterInit(p1, bDesc, &i1); + fts5DoclistIterInit(p2, bDesc, &i2); while( i1.aPoslist!=0 || i2.aPoslist!=0 ){ if( i2.aPoslist==0 || (i1.aPoslist && - ( (!bAsc && i1.iRowid>i2.iRowid) || (bAsc && i1.iRowidi2.iRowid) || (!bDesc && i1.iRowidrc, bAsc, &out, &iLastRowid, i1.iRowid); + fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i1.iRowid); fts5BufferAppendVarint(&p->rc, &out, i1.nPoslist); fts5BufferAppendBlob(&p->rc, &out, i1.nPoslist, i1.aPoslist); fts5DoclistIterNext(&i1); } else if( i1.aPoslist==0 || i2.iRowid!=i1.iRowid ){ /* Copy entry from i2 */ - fts5MergeAppendDocid(&p->rc, bAsc, &out, &iLastRowid, i2.iRowid); + fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i2.iRowid); fts5BufferAppendVarint(&p->rc, &out, i2.nPoslist); fts5BufferAppendBlob(&p->rc, &out, i2.nPoslist, i2.aPoslist); fts5DoclistIterNext(&i2); } else{ @@ -3807,11 +3805,11 @@ Fts5PoslistWriter writer; memset(&writer, 0, sizeof(writer)); /* Merge the two position lists. */ - fts5MergeAppendDocid(&p->rc, bAsc, &out, &iLastRowid, i2.iRowid); + fts5MergeAppendDocid(&p->rc, bDesc, &out, &iLastRowid, i2.iRowid); fts5BufferZero(&tmp); sqlite3Fts5PoslistReaderInit(-1, i1.aPoslist, i1.nPoslist, &r1); sqlite3Fts5PoslistReaderInit(-1, i2.aPoslist, i2.nPoslist, &r2); while( p->rc==SQLITE_OK && (r1.bEof==0 || r2.bEof==0) ){ i64 iNew; @@ -3845,11 +3843,11 @@ *p2 = tmp; } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ - int bAsc, /* True for "ORDER BY rowid ASC" */ + int bDesc, /* True for "ORDER BY rowid DESC" */ const u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5IndexIter *pIter /* Populate this object */ ){ Fts5Structure *pStruct; @@ -3876,47 +3874,47 @@ const u8 *pTerm = fts5MultiIterTerm(p1, &nTerm); assert( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 ); if( nTerm0 - && ((!bAsc && iRowid>=iLastRowid) || (bAsc && iRowid<=iLastRowid)) + && ((!bDesc && iRowid<=iLastRowid) || (bDesc && iRowid>=iLastRowid)) ){ for(i=0; p->rc==SQLITE_OK && doclist.n; i++){ assert( irc, &doclist, iRowid); - }else if( bAsc==0 ){ + }else if( bDesc ){ fts5BufferAppendVarint(&p->rc, &doclist, iLastRowid - iRowid); }else{ fts5BufferAppendVarint(&p->rc, &doclist, iRowid - iLastRowid); } iLastRowid = iRowid; fts5MultiIterPoslist(p, p1, 1, &doclist); } for(i=0; ipDoclist = pDoclist; - fts5DoclistIterInit(&doclist, bAsc, pIter->pDoclist); + fts5DoclistIterInit(&doclist, bDesc, pIter->pDoclist); } } fts5StructureRelease(pStruct); sqlite3_free(aBuf); @@ -4271,12 +4269,12 @@ fts5MultiIterNew(p, pRet->pStruct, iIdx, 1, flags, (const u8*)pToken, nToken, -1, 0, &pRet->pMulti ); } }else{ - int bAsc = (flags & FTS5INDEX_QUERY_ASC)!=0; - fts5SetupPrefixIter(p, bAsc, (const u8*)pToken, nToken, pRet); + int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0; + fts5SetupPrefixIter(p, bDesc, (const u8*)pToken, nToken, pRet); } } if( p->rc ){ sqlite3Fts5IterClose(pRet); @@ -4319,12 +4317,12 @@ ** descending rowid order. */ static void fts5DoclistIterNextFrom(Fts5DoclistIter *p, i64 iMatch){ do{ i64 iRowid = p->iRowid; - if( p->bAsc!=0 && iRowid>=iMatch ) break; - if( p->bAsc==0 && iRowid<=iMatch ) break; + if( p->bDesc==0 && iRowid>=iMatch ) break; + if( p->bDesc!=0 && iRowid<=iMatch ) break; fts5DoclistIterNext(p); }while( p->aPoslist ); } /* @@ -4600,11 +4598,11 @@ iOff += fts5DecodePoslist(pRc, pBuf, &a[iOff], MIN(n-iOff, nPos)); if( iOff { ...} # # where each element is a list of phrase matches in the # same form as returned by auxiliary scalar function fts5_test(). # -proc matchdata {bPos expr {bAsc 0}} { +proc matchdata {bPos expr {bAsc 1}} { set tclexpr [db one {SELECT fts5_expr_tcl($expr, 'nearset $cols', 'x', 'y')}] set res [list] #puts $tclexpr @@ -305,10 +306,12 @@ #------------------------------------------------------------------------- # Test phrase queries. # foreach {tn phrase} { + 8 "c" + 1 "o" 2 "b q" 3 "e a e" 4 "m d g q q b k b w f q q p p" 5 "l o o l v v k" @@ -398,12 +401,12 @@ do_execsql_test 6.integrity { INSERT INTO xx(xx) VALUES('integrity-check'); } #db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM xx_data} {puts $r} foreach {bAsc sql} { - 0 {SELECT rowid FROM xx WHERE xx MATCH $expr} - 1 {SELECT rowid FROM xx WHERE xx MATCH $expr ORDER BY rowid ASC} + 1 {SELECT rowid FROM xx WHERE xx MATCH $expr} + 0 {SELECT rowid FROM xx WHERE xx MATCH $expr ORDER BY rowid DESC} } { foreach {tn expr} { 0.1 x 1 { NEAR(r c) } 2 { NEAR(r c, 5) } Index: ext/fts5/test/fts5ad.test ================================================================== --- ext/fts5/test/fts5ad.test +++ ext/fts5/test/fts5ad.test @@ -34,11 +34,11 @@ 2 {i*} {3 2} 3 {t*} {3 1} 4 {r*} {3 1} } { do_execsql_test 1.$tn { - SELECT rowid FROM yy WHERE yy MATCH $match + SELECT rowid FROM yy WHERE yy MATCH $match ORDER BY rowid DESC } $res } foreach {tn match res} { 5 {c*} {1} @@ -45,11 +45,11 @@ 6 {i*} {2 3} 7 {t*} {1 3} 8 {r*} {1 3} } { do_execsql_test 1.$tn { - SELECT rowid FROM yy WHERE yy MATCH $match ORDER BY rowid ASC + SELECT rowid FROM yy WHERE yy MATCH $match } $res } foreach {T create} { 2 { @@ -192,12 +192,12 @@ } return $ret } foreach {bAsc sql} { - 0 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix} - 1 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix ORDER BY rowid ASC} + 1 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix} + 0 {SELECT rowid FROM t1 WHERE t1 MATCH $prefix ORDER BY rowid DESC} } { foreach {tn prefix} { 1 {a*} 2 {ab*} 3 {abc*} 4 {abcd*} 5 {abcde*} 6 {f*} 7 {fg*} 8 {fgh*} 9 {fghi*} 10 {fghij*} 11 {k*} 12 {kl*} 13 {klm*} 14 {klmn*} 15 {klmno*} Index: ext/fts5/test/fts5ae.test ================================================================== --- ext/fts5/test/fts5ae.test +++ ext/fts5/test/fts5ae.test @@ -107,12 +107,12 @@ INSERT INTO t3 VALUES('k x j r m a d o i z j', 'r t t t f e b r x i v j v g o'); SELECT rowid, fts5_test_poslist(t3) FROM t3 WHERE t3 MATCH 'a OR b AND c'; } { - 3 0.0.5 1 {0.0.6 1.0.9 0.0.10 0.0.12 1.0.15 2.1.2} + 3 0.0.5 } #------------------------------------------------------------------------- # do_execsql_test 4.0 { @@ -188,12 +188,12 @@ } do_execsql_test 6.2 { SELECT rowid, fts5_test_tokenize(t6) FROM t6 WHERE t6 MATCH 't*' } { - 2 {{horatio than are} {dreamt of in your philosophy}} 1 {{there are more} {things in heaven and earth}} + 2 {{horatio than are} {dreamt of in your philosophy}} } #------------------------------------------------------------------------- # Test the xQueryPhrase() API # Index: ext/fts5/test/fts5ak.test ================================================================== --- ext/fts5/test/fts5ak.test +++ ext/fts5/test/fts5ak.test @@ -38,23 +38,23 @@ } do_execsql_test 1.2 { SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e'; } { - {g d a [e] h a b c f j} - {i c c f a d g h j [e]} - {j f c [e] d a h j d b} + {[e] j a [e] f h b f h h} + {d c j d c j b c g [e]} {i a d [e] g j g d a a} - {d c j d c j b c g [e]} - {[e] j a [e] f h b f h h} + {j f c [e] d a h j d b} + {i c c f a d g h j [e]} + {g d a [e] h a b c f j} } do_execsql_test 1.3 { SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'h + d'; } { - {j f [h d] g h i b d f} {[h d] b j c c g a c a} + {j f [h d] g h i b d f} } do_execsql_test 1.4 { SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d'; } { @@ -62,16 +62,16 @@ } do_execsql_test 1.5 { SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'e e e' } { - {g d a [e] h a b c f j} - {i c c f a d g h j [e]} - {j f c [e] d a h j d b} + {[e] j a [e] f h b f h h} + {d c j d c j b c g [e]} {i a d [e] g j g d a a} - {d c j d c j b c g [e]} - {[e] j a [e] f h b f h h} + {j f c [e] d a h j d b} + {i c c f a d g h j [e]} + {g d a [e] h a b c f j} } do_execsql_test 1.6 { SELECT highlight(ft1, 0, '[', ']') FROM ft1 WHERE ft1 MATCH 'd + d d + d'; } { @@ -131,13 +131,13 @@ -- '[a b c] x [c d e]' -- '[a b c] [c d e]' -- '[a b c d e]' SELECT highlight(ft, 0, '[', ']') FROM ft WHERE ft MATCH 'a+b+c AND c+d+e'; } { - {[a b c d e]} + {[a b c] x [c d e]} {[a b c] [c d e]} - {[a b c] x [c d e]} + {[a b c d e]} } finish_test Index: ext/fts5/test/fts5al.test ================================================================== --- ext/fts5/test/fts5al.test +++ ext/fts5/test/fts5al.test @@ -102,11 +102,11 @@ proc rowidtest {cmd} { $cmd xRowid } sqlite3_fts5_create_function db rowidtest rowidtest do_execsql_test 3.3.1 { SELECT rowidtest(t1) FROM t1 WHERE t1 MATCH 'q' -} {2 1} +} {1 2} proc insttest {cmd} { set res [list] for {set i 0} {$i < [$cmd xInstCount]} {incr i} { lappend res [$cmd xInst $i] @@ -116,19 +116,19 @@ sqlite3_fts5_create_function db insttest insttest do_execsql_test 3.4.1 { SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'q' } { - {{0 0 5}} {{0 0 0}} + {{0 0 5}} } do_execsql_test 3.4.2 { SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'r+e OR w' } { - {{0 0 2} {1 0 4}} {{1 0 1}} + {{0 0 2} {1 0 4}} } proc coltest {cmd} { list [$cmd xColumnSize 0] [$cmd xColumnText 0] } @@ -135,11 +135,12 @@ sqlite3_fts5_create_function db coltest coltest do_execsql_test 3.5.1 { SELECT coltest(t1) FROM t1 WHERE t1 MATCH 'q' } { - {6 {y t r e w q}} {6 {q w e r t y}} + {6 {q w e r t y}} + {6 {y t r e w q}} } #------------------------------------------------------------------------- # Tests for remapping the "rank" column. # @@ -186,11 +187,11 @@ do_execsql_test 4.1.3 { SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' AND rank MATCH 'firstinst()' ORDER BY rank DESC } { - 5 103 9 102 6 9 10 8 3 6 2 4 7 0 1 0 + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 } do_execsql_test 4.1.4 { INSERT INTO t2(t2, rank) VALUES('rank', 'firstinst()'); SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rowid ASC @@ -200,18 +201,18 @@ } do_execsql_test 4.1.5 { SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rank DESC } { - 5 103 9 102 6 9 10 8 3 6 2 4 7 0 1 0 + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 } do_execsql_test 4.1.6 { INSERT INTO t2(t2, rank) VALUES('rank', 'firstinst ( ) '); SELECT rowid, rank FROM t2 WHERE t2 MATCH 'a' ORDER BY rank DESC } { - 5 103 9 102 6 9 10 8 3 6 2 4 7 0 1 0 + 5 103 9 102 6 9 10 8 3 6 2 4 1 0 7 0 } proc rowidplus {cmd ival} { expr [$cmd xRowid] + $ival } @@ -255,18 +256,18 @@ do_execsql_test 4.3.2 { SELECT * FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(4)' ORDER BY rank ASC } { - {a four} {a five} {a one} {a two} {a three} + {a four} {a one} {a five} {a two} {a three} } do_execsql_test 4.3.3 { SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH 'rowidmod(3)' ORDER BY rank ASC } { - {a three} 0 {a four} 1 {a one} 1 {a five} 2 {a two} 2 + {a three} 0 {a one} 1 {a four} 1 {a two} 2 {a five} 2 } finish_test Index: ext/fts5/test/fts5content.test ================================================================== --- ext/fts5/test/fts5content.test +++ ext/fts5/test/fts5content.test @@ -24,42 +24,42 @@ INSERT INTO f1(rowid, a, b) VALUES(3, 'three', 't h r e e'); } do_execsql_test 1.2 { SELECT rowid FROM f1 WHERE f1 MATCH 'o'; -} {2 1} +} {1 2} do_execsql_test 1.3 { INSERT INTO f1(a, b) VALUES('four', 'f o u r'); SELECT rowid FROM f1 WHERE f1 MATCH 'o'; -} {4 2 1} +} {1 2 4} do_execsql_test 1.4 { SELECT rowid, a, b FROM f1 WHERE f1 MATCH 'o'; -} {4 {} {} 2 {} {} 1 {} {}} +} {1 {} {} 2 {} {} 4 {} {}} do_execsql_test 1.5 { SELECT rowid, highlight(f1, 0, '[', ']') FROM f1 WHERE f1 MATCH 'o'; -} {4 {} 2 {} 1 {}} +} {1 {} 2 {} 4 {}} do_execsql_test 1.6 { SELECT rowid, highlight(f1, 0, '[', ']') IS NULL FROM f1 WHERE f1 MATCH 'o'; -} {4 1 2 1 1 1} +} {1 1 2 1 4 1} do_execsql_test 1.7 { SELECT rowid, snippet(f1, -1, '[', ']', '...', 5) IS NULL FROM f1 WHERE f1 MATCH 'o'; -} {4 1 2 1 1 1} +} {1 1 2 1 4 1} do_execsql_test 1.8 { SELECT rowid, snippet(f1, 1, '[', ']', '...', 5) IS NULL FROM f1 WHERE f1 MATCH 'o'; -} {4 1 2 1 1 1} +} {1 1 2 1 4 1} do_execsql_test 1.9 { SELECT rowid FROM f1; -} {4 3 2 1} +} {1 2 3 4} do_execsql_test 1.10 { SELECT * FROM f1; } {{} {} {} {} {} {} {} {}} @@ -83,15 +83,15 @@ INSERT INTO f1(f1, rowid, a, b) VALUES('delete', 2, 'two', 't w o'); } {} do_execsql_test 1.16 { SELECT rowid FROM f1 WHERE f1 MATCH 'o'; -} {4 1} +} {1 4} do_execsql_test 1.17 { SELECT rowid FROM f1; -} {4 3 1} +} {1 3 4} #------------------------------------------------------------------------- # External content tables # reset_db Index: ext/fts5/test/fts5corrupt.test ================================================================== --- ext/fts5/test/fts5corrupt.test +++ ext/fts5/test/fts5corrupt.test @@ -51,25 +51,24 @@ db_restore_and_reopen #db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r} - #-------------------------------------------------------------------- +# do_execsql_test 2.0 { CREATE VIRTUAL TABLE t2 USING fts5(x); - INSERT INTO t2(t2, rank) VALUES('pgsz', 32); -} -do_test 2.1 { - db transaction { - for {set i 0} {$i < 20} {incr i} { - execsql { INSERT INTO t2 VALUES('xxxxxxxxxx') } - } - for {set i 0} {$i < 20} {incr i} { - execsql { INSERT INTO t2 VALUES('xxxxxxxxxzzzz') } - } + INSERT INTO t2(t2, rank) VALUES('pgsz', 64); +} +db func rnddoc fts5_rnddoc +do_test 2.1 { + for {set i 0} {$i < 500} {incr i} { + execsql { INSERT INTO t2 VALUES(rnddoc(50)) } + execsql { INSERT INTO t2(t2) VALUES('integrity-check') } } } {} -db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t2_data} {puts $r} + +#-------------------------------------------------------------------- +# finish_test Index: ext/fts5/test/fts5fault1.test ================================================================== --- ext/fts5/test/fts5fault1.test +++ ext/fts5/test/fts5fault1.test @@ -88,17 +88,17 @@ faultsim_save_and_close foreach {tn expr res} { 1 { dk } 7 2 { m f } 1 - 3 { f* } {10 9 8 6 5 4 3 1} - 4 { m OR f } {10 9 8 5 4 1} + 3 { f* } {1 3 4 5 6 8 9 10} + 4 { m OR f } {1 4 5 8 9 10} 5 { sn + gh } {5} 6 { "sn gh" } {5} 7 { NEAR(r a, 5) } {9} - 8 { m* f* } {10 9 8 6 4 1} - 9 { m* + f* } {8 1} + 8 { m* f* } {1 4 6 8 9 10} + 9 { m* + f* } {1 8} } { do_faultsim_test 4.$tn -prep { faultsim_restore_and_reopen } -body " execsql { SELECT rowid FROM t2 WHERE t2 MATCH '$expr' } @@ -300,11 +300,11 @@ db func rnddoc rnddoc do_test 8.0 { execsql { CREATE VIRTUAL TABLE x1 USING fts5(a) } set ::res [list] - for {set i 100} {$i>0} {incr i -1} { + for {set i 1} {$i<100} {incr i 1} { execsql { INSERT INTO x1 VALUES( rnddoc(50) ) } lappend ::res $i } } {} Index: ext/fts5/test/fts5rowid.test ================================================================== --- ext/fts5/test/fts5rowid.test +++ ext/fts5/test/fts5rowid.test @@ -170,11 +170,11 @@ execsql COMMIT } {} do_execsql_test 5.1 { SELECT rowid FROM x4 WHERE x4 MATCH 'a' -} {4 3 2 1} +} {1 2 3 4} set res [db one {SELECT count(*) FROM x4_data}] do_execsql_test 5.2 { SELECT count(fts5_decode(rowid, block)) FROM x4_data; } $res