Have fts5 store rowids in ascending order. Query speed is virtually the same regardless of rowid order, and ascending order makes some insert optimizations easier.

FossilOrigin-Name: 5206ca6005bfa9dfc7346d4b89430c9748d32c10
This commit is contained in:
dan 2015-01-24 19:57:03 +00:00
parent 641cb4360a
commit 8ac3025419
18 changed files with 290 additions and 259 deletions

View File

@ -505,7 +505,7 @@ static int fts5OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
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;
}
@ -652,7 +652,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
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;
@ -680,7 +680,7 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bAsc){
pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
(zRankArgs ? ", " : ""),
(zRankArgs ? zRankArgs : ""),
bAsc ? "ASC" : "DESC"
bDesc ? "DESC" : "ASC"
);
if( zSql==0 ){
rc = SQLITE_NOMEM;
@ -706,9 +706,9 @@ static int fts5CursorFirstSorted(Fts5Table *pTab, Fts5Cursor *pCsr, int bAsc){
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);
}
@ -873,7 +873,7 @@ static int fts5FilterMethod(
){
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 );
@ -894,7 +894,7 @@ static int fts5FilterMethod(
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;
@ -913,9 +913,9 @@ static int fts5FilterMethod(
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);
}
}
}

View File

@ -229,7 +229,7 @@ typedef struct Fts5IndexIter Fts5IndexIter;
** 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.
@ -365,6 +365,13 @@ int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v);
*/
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.
*/
@ -395,6 +402,11 @@ int sqlite3Fts5HashIterate(
int (*xTermDone)(void*)
);
int sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
const char *pTerm, int nTerm, /* Query term */
Fts5Data **ppData /* OUT: Query result */
);
/*
@ -470,7 +482,7 @@ int sqlite3Fts5ExprNew(
);
/*
** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bAsc);
** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr);
** rc = sqlite3Fts5ExprNext(pExpr)
** ){
@ -478,7 +490,7 @@ int sqlite3Fts5ExprNew(
** 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*);

View File

@ -32,7 +32,7 @@ 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 */
};
@ -600,9 +600,9 @@ static int fts5ExprNearAdvanceAll(
}
/*
** 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
@ -610,7 +610,7 @@ static int fts5ExprNearAdvanceAll(
*/
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 */
@ -619,14 +619,14 @@ static int fts5ExprAdvanceto(
i64 iRowid;
iRowid = sqlite3Fts5IterRowid(pIter);
if( (bAsc==0 && iRowid>iLast) || (bAsc && iRowid<iLast) ){
if( (bDesc==0 && iLast>iRowid) || (bDesc && iLast<iRowid) ){
sqlite3Fts5IterNextFrom(pIter, iLast);
if( sqlite3Fts5IterEof(pIter) ){
*pbEof = 1;
return 1;
}
iRowid = sqlite3Fts5IterRowid(pIter);
assert( (bAsc==0 && iRowid<=iLast) || (bAsc==1 && iRowid>=iLast) );
assert( (bDesc==0 && iRowid>=iLast) || (bDesc==1 && iRowid<=iLast) );
}
*piLast = iRowid;
@ -656,12 +656,13 @@ static int fts5ExprNearNextRowidMatch(
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;
}
@ -673,7 +674,7 @@ static int fts5ExprNearNextRowidMatch(
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;
}
}
@ -774,7 +775,7 @@ static int fts5ExprNearInitAll(
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 );
@ -810,7 +811,7 @@ static int fts5NodeCompare(
){
if( p2->bEof ) return -1;
if( p1->bEof ) return +1;
if( pExpr->bAsc ){
if( pExpr->bDesc==0 ){
if( p1->iRowid<p2->iRowid ) return -1;
return (p1->iRowid > p2->iRowid);
}else{
@ -911,18 +912,17 @@ static int fts5ExprNodeNextMatch(
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;
}
}
@ -1003,18 +1003,18 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
/*
** 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;

View File

@ -55,7 +55,7 @@ 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 */
@ -64,6 +64,16 @@ struct Fts5HashEntry {
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.
@ -161,25 +171,6 @@ static int fts5HashResize(Fts5Hash *pHash){
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 */
@ -192,7 +183,7 @@ int sqlite3Fts5HashWrite(
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;
}
@ -214,26 +205,27 @@ int sqlite3Fts5HashWrite(
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;
@ -250,9 +242,11 @@ int sqlite3Fts5HashWrite(
/* 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;
@ -379,28 +373,31 @@ int sqlite3Fts5HashIterate(
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 && iOff<pList->nData ){
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;
@ -409,5 +406,3 @@ int sqlite3Fts5HashIterate(
return rc;
}

View File

@ -44,7 +44,7 @@
#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:
@ -270,7 +270,6 @@ int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
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;
@ -311,7 +310,7 @@ struct Fts5Index {
};
struct Fts5DoclistIter {
int bAsc;
int bDesc; /* True for DESC order, false for ASC */
u8 *a;
int n;
int i;
@ -333,15 +332,6 @@ struct Fts5IndexIter {
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
@ -1483,6 +1473,11 @@ static void fts5DlidxIterFree(Fts5DlidxIter *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.
*/
@ -1503,8 +1498,15 @@ static void fts5SegIterNextPage(
}
/*
** 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 */
@ -1569,11 +1571,6 @@ static void fts5SegIterInit(
}
}
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.
@ -1598,7 +1595,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
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;
@ -1678,7 +1675,7 @@ static int fts5SegIterIsDelete(
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);
@ -1713,7 +1710,7 @@ static void fts5SegIterNext(
iOff += fts5GetVarint32(&a[iOff], nPos);
iOff += nPos;
getVarint(&a[iOff], (u64*)&iDelta);
pIter->iRowid += iDelta;
pIter->iRowid -= iDelta;
}else{
fts5SegIterReverseNewPage(p, pIter);
}
@ -1748,7 +1745,7 @@ static void fts5SegIterNext(
pIter->iLeafOffset += fts5GetVarint32(&a[iOff], nKeep);
}
}else{
pIter->iRowid -= iDelta;
pIter->iRowid += iDelta;
}
}else{
iOff = 0;
@ -1922,7 +1919,7 @@ static void fts5SegIterSeekInit(
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;
@ -1980,13 +1977,13 @@ static void fts5SegIterSeekInit(
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);
}
}
@ -2042,7 +2039,7 @@ static int fts5MultiIterDoCompare(Fts5MultiSegIter *pIter, int iOut){
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 ){
@ -2056,35 +2053,6 @@ static int fts5MultiIterDoCompare(Fts5MultiSegIter *pIter, int iOut){
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; i<pIter->nSeg; 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.
@ -2170,6 +2138,36 @@ static void fts5SegIterNextFrom(
}
}
/*
** Free the iterator object passed as the second argument.
*/
static void fts5MultiIterFree(Fts5Index *p, Fts5MultiSegIter *pIter){
if( pIter ){
int i;
for(i=0; i<pIter->nSeg; 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.
**
@ -2248,7 +2246,7 @@ static void fts5MultiIterNew(
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. */
@ -2328,8 +2326,8 @@ static void fts5MultiIterNextFrom(
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;
}
}
@ -2794,8 +2792,8 @@ static void fts5WriteAppendRowid(
if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
}else{
assert( p->rc || iRowid<pWriter->iPrevRowid );
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;
@ -3711,10 +3709,10 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
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);
@ -3729,13 +3727,13 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
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);
}
@ -3744,14 +3742,14 @@ static void fts5DoclistIterInit(
*/
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);
@ -3769,7 +3767,7 @@ static void fts5MergeAppendDocid(
*/
static void fts5MergePrefixLists(
Fts5Index *p, /* FTS5 backend object */
int bAsc,
int bDesc,
Fts5Buffer *p1, /* First list to merge */
Fts5Buffer *p2 /* Second list to merge */
){
@ -3782,21 +3780,21 @@ static void fts5MergePrefixLists(
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.iRowid<i2.iRowid) )
( (bDesc && i1.iRowid>i2.iRowid) || (!bDesc && i1.iRowid<i2.iRowid) )
)){
/* Copy entry from i1 */
fts5MergeAppendDocid(&p->rc, 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);
@ -3809,7 +3807,7 @@ static void fts5MergePrefixLists(
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);
@ -3847,7 +3845,7 @@ static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){
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 */
@ -3878,7 +3876,7 @@ static void fts5SetupPrefixIter(
if( nTerm<nToken || memcmp(pToken, pTerm, nToken) ) break;
if( doclist.n>0
&& ((!bAsc && iRowid>=iLastRowid) || (bAsc && iRowid<=iLastRowid))
&& ((!bDesc && iRowid<=iLastRowid) || (bDesc && iRowid>=iLastRowid))
){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
@ -3887,14 +3885,14 @@ static void fts5SetupPrefixIter(
fts5BufferSwap(&doclist, &aBuf[i]);
fts5BufferZero(&doclist);
}else{
fts5MergePrefixLists(p, bAsc, &doclist, &aBuf[i]);
fts5MergePrefixLists(p, bDesc, &doclist, &aBuf[i]);
fts5BufferZero(&aBuf[i]);
}
}
}
if( doclist.n==0 ){
fts5BufferAppendVarint(&p->rc, &doclist, iRowid);
}else if( bAsc==0 ){
}else if( bDesc ){
fts5BufferAppendVarint(&p->rc, &doclist, iLastRowid - iRowid);
}else{
fts5BufferAppendVarint(&p->rc, &doclist, iRowid - iLastRowid);
@ -3904,7 +3902,7 @@ static void fts5SetupPrefixIter(
}
for(i=0; i<nBuf; i++){
fts5MergePrefixLists(p, bAsc, &doclist, &aBuf[i]);
fts5MergePrefixLists(p, bDesc, &doclist, &aBuf[i]);
fts5BufferFree(&aBuf[i]);
}
fts5MultiIterFree(p, p1);
@ -3914,7 +3912,7 @@ static void fts5SetupPrefixIter(
fts5BufferFree(&doclist);
}else{
pIter->pDoclist = pDoclist;
fts5DoclistIterInit(&doclist, bAsc, pIter->pDoclist);
fts5DoclistIterInit(&doclist, bDesc, pIter->pDoclist);
}
}
@ -4273,8 +4271,8 @@ int sqlite3Fts5IndexQuery(
);
}
}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);
}
}
@ -4321,8 +4319,8 @@ int sqlite3Fts5IterNext(Fts5IndexIter *pIter){
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 );
}
@ -4602,7 +4600,7 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
i64 iDelta;
iOff += sqlite3GetVarint(&a[iOff], (u64*)&iDelta);
if( iDelta==0 ) return iOff;
iDocid -= iDelta;
iDocid += iDelta;
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " rowid=%lld", iDocid);
}
}
@ -4692,7 +4690,6 @@ static void fts5DecodeFunction(
}
fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
assert( iRowidOff==0 || iOff==iRowidOff );
if( iRowidOff ){
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], n-iOff);

View File

@ -185,7 +185,9 @@ for {set i 1} {$i <= 10} {incr i} {
}
execsql { INSERT INTO t1(t1) VALUES('integrity-check'); }
} {}
if {$i==2} break
}
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}
#-------------------------------------------------------------------------
#
@ -312,7 +314,7 @@ do_execsql_test 13.1 {
do_execsql_test 13.2 {
SELECT rowid FROM t1 WHERE t1 MATCH 'o';
} {2 1}
} {1 2}
do_execsql_test 13.4 {
DELETE FROM t1 WHERE rowid=2;

View File

@ -30,11 +30,11 @@ do_execsql_test 1.0 {
}
do_execsql_test 1.1 {
SELECT * FROM t1;
SELECT * FROM t1 ORDER BY rowid DESC;
} { forty five {one two} {three four} hello world }
do_execsql_test 1.2 {
SELECT rowid FROM t1;
SELECT rowid FROM t1 ORDER BY rowid DESC;
} {45 2 1}
do_execsql_test 1.3 {
@ -90,7 +90,12 @@ foreach {tn expr res} {
9 y {6}
10 z {6}
} {
do_execsql_test 2.7.$tn { SELECT rowid FROM t1 WHERE t1 MATCH $expr } $res
do_execsql_test 2.7.$tn.1 {
SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid DESC
} $res
do_execsql_test 2.7.$tn.2 {
SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid ASC
} [lsort -integer $res]
}
#-------------------------------------------------------------------------
@ -127,7 +132,7 @@ foreach {tn expr res} {
7 {"abashing abases abasement abaft abashing"} {8}
} {
do_execsql_test 3.2.$tn {
SELECT rowid FROM t1 WHERE t1 MATCH $expr
SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid DESC
} $res
}
@ -145,7 +150,7 @@ foreach {tn expr res} {
7 {"abashing abases abasement abaft abashing"} {8}
} {
do_execsql_test 3.4.$tn {
SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid ASC
SELECT rowid FROM t1 WHERE t1 MATCH $expr
} $res
}
@ -165,11 +170,11 @@ foreach {tn doc} [list \
do_execsql_test 4.3 {
SELECT rowid FROM s1 WHERE s1 MATCH 'x'
} {2 1}
} {1 2}
do_execsql_test 4.4 {
SELECT rowid FROM s1 WHERE s1 MATCH '"a x"'
} {2 1}
} {1 2}
#-------------------------------------------------------------------------
# Check that a special case of segment promotion works. The case is where
@ -233,6 +238,23 @@ do_test 5.4 {
fts5_level_segs s2
} {2 0}
#-------------------------------------------------------------------------
#
do_execsql_test 6.0 {
CREATE VIRTUAL TABLE s3 USING fts5(x);
BEGIN;
INSERT INTO s3 VALUES('a b c');
INSERT INTO s3 VALUES('A B C');
}
do_execsql_test 6.1 {
SELECT rowid FROM s3 WHERE s3 MATCH 'a'
} {2 1}
do_execsql_test 6.2 {
COMMIT;
SELECT rowid FROM s3 WHERE s3 MATCH 'a'
} {2 1}
finish_test

View File

@ -134,6 +134,7 @@ do_test 1.1 {
foreach {id x y} $data {
execsql { INSERT INTO xx(rowid, x, y) VALUES($id, $x, $y) }
}
execsql { INSERT INTO xx(xx) VALUES('integrity-check') }
} {}
# Usage:
@ -253,7 +254,7 @@ proc instcompare {lhs rhs} {
# where each <phrase X matches> 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]
@ -307,6 +308,8 @@ sqlite3_fts5_create_function db fts5_test_poslist fts5_test_poslist
# Test phrase queries.
#
foreach {tn phrase} {
8 "c"
1 "o"
2 "b q"
3 "e a e"
@ -400,8 +403,8 @@ do_execsql_test 6.integrity {
}
#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

View File

@ -36,7 +36,7 @@ foreach {tn match res} {
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
}
@ -47,7 +47,7 @@ foreach {tn match res} {
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
}
@ -194,8 +194,8 @@ foreach {T create} {
}
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*}

View File

@ -109,8 +109,8 @@ do_execsql_test 3.3 {
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
}
#-------------------------------------------------------------------------
@ -190,8 +190,8 @@ do_execsql_test 6.1 {
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}}
}
#-------------------------------------------------------------------------

View File

@ -40,19 +40,19 @@ do_execsql_test 1.1 {
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}
{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}
{d c j d c j b c g [e]}
{i a d [e] g j g d a a}
{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 {
@ -64,12 +64,12 @@ do_execsql_test 1.4 {
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}
{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}
{d c j d c j b c g [e]}
{i a d [e] g j g d a a}
{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 {
@ -133,9 +133,9 @@ do_execsql_test 3.1 {
-- '[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] [c d e]}
{[a b c] x [c d e]}
{[a b c] [c d e]}
{[a b c d e]}
}

View File

@ -104,7 +104,7 @@ 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]
@ -118,15 +118,15 @@ 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} {
@ -137,7 +137,8 @@ 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}}
}
#-------------------------------------------------------------------------
@ -188,7 +189,7 @@ do_execsql_test 4.1.3 {
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 {
@ -202,14 +203,14 @@ do_execsql_test 4.1.4 {
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} {
@ -257,14 +258,14 @@ do_execsql_test 4.3.2 {
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
}

View File

@ -26,38 +26,38 @@ do_execsql_test 1.1 {
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;
@ -85,11 +85,11 @@ do_execsql_test 1.15 {
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

View File

@ -53,23 +53,22 @@ 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);
INSERT INTO t2(t2, rank) VALUES('pgsz', 64);
}
db func rnddoc fts5_rnddoc
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') }
}
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

View File

@ -90,13 +90,13 @@ 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
@ -302,7 +302,7 @@ 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
}

View File

@ -172,7 +172,7 @@ do_test 5.0 {
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 {

View File

@ -1,5 +1,5 @@
C Fix\scompression\sof\skeys\sstored\son\sinternal\ssegment\sb-tree\snodes\sby\sfts5.
D 2015-01-23T17:43:21.454
C Have\sfts5\sstore\srowids\sin\sascending\sorder.\sQuery\sspeed\sis\svirtually\sthe\ssame\sregardless\sof\srowid\sorder,\sand\sascending\sorder\smakes\ssome\sinsert\soptimizations\seasier.
D 2015-01-24T19:57:03.097
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5407a688f4d77a05c18a8142be8ae5a2829dd610
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -104,15 +104,15 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl 4199cb887040ee3c3cd59a5171ddb0566904586e
F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
F ext/fts5/fts5.c 41b852b654f79f522668bc7ba292755fb261f855
F ext/fts5/fts5.c f2e899fba27ca33c8897635752c4c83a40dcb18d
F ext/fts5/fts5.h f931954065693898d26c51f23f1d27200184a69a
F ext/fts5/fts5Int.h 1d8f968b8ff71de15176acf8f4b14a2bdebcb6e3
F ext/fts5/fts5Int.h e3b9344d8209c9639825c711662d5d039eb70322
F ext/fts5/fts5_aux.c 549aef152b0fd46020f5595d861b1fd60b3f9b4f
F ext/fts5/fts5_buffer.c 32dd3c950392346ca69a0f1803501766c5c954f9
F ext/fts5/fts5_config.c e3421a76c2abd33a05ac09df0c97c64952d1e700
F ext/fts5/fts5_expr.c 8a0e643768666dc2bffe74104141274809699808
F ext/fts5/fts5_hash.c 7a87f9f2eae2216c710064821fa0621ac6a8ce7b
F ext/fts5/fts5_index.c dda2ed8dab9910aedd8de0169ca029c5336b9e42
F ext/fts5/fts5_expr.c 473e3428a9a637fa6e61d64d8ca3796ec57a58e9
F ext/fts5/fts5_hash.c 4ab952b75f27d5ed3ef0f3b4f7fa1464744483e8
F ext/fts5/fts5_index.c b3e8e38c70178a638f4b0a183694db60ecde5366
F ext/fts5/fts5_storage.c f7c12c9f454b2a525827b3d85fd222789236f548
F ext/fts5/fts5_tcl.c 1293fac2bb26903fd3d5cdee59c5885ba7e620d5
F ext/fts5/fts5_tokenize.c 7c61d5c35c3449597bdeaa54dd48afe26852c7b0
@ -120,30 +120,30 @@ F ext/fts5/fts5_unicode2.c 9c7dd640d1f014bf5c3ee029759adfbb4d7e95a9
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl d9ea79fdbc9ecbb3541bf89d13ee0e03a8dc3d32
F ext/fts5/test/fts5aa.test 8ddbbcbedab67101dc9a86fd5c39d78b0e06515f
F ext/fts5/test/fts5ab.test 3f3ad2fb9ed60a0df57b626fa6fe6ef41d4deee0
F ext/fts5/test/fts5ac.test 48181b7c873da0e3b4a3316760fcb90d88e7fbd8
F ext/fts5/test/fts5ad.test 3b01eec8516d5631909716514e2e585a45ef0eb1
F ext/fts5/test/fts5ae.test 014d5be2f5f70407fb032d4f27704116254797c3
F ext/fts5/test/fts5aa.test e77e28ac85c70891fc2603ff4b15de571eca628f
F ext/fts5/test/fts5ab.test 127769288519ed549c57d7e11628dbe5b9952ad5
F ext/fts5/test/fts5ac.test 1dfa0751bcf32fd9cfaad1557b7729950e5cc930
F ext/fts5/test/fts5ad.test 6c970531caf865b65f4e1dd9d6d43bd6ea37d754
F ext/fts5/test/fts5ae.test 347c96db06aab23ff00cf6a6b4064a8dbb182e42
F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
F ext/fts5/test/fts5ag.test ec3e119b728196620a31507ef503c455a7a73505
F ext/fts5/test/fts5ah.test 17ba8e197a781ca10548b7260e39ed8269d24b93
F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37
F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8
F ext/fts5/test/fts5ak.test dc7bcd087dea0451ec40bba173962a0ba3a1d8ce
F ext/fts5/test/fts5al.test 633fdb3d974629d01ba7734d180dbc2ad8ed772a
F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592
F ext/fts5/test/fts5al.test 6a5717faaf7f1e0e866360022d284903f3a4eede
F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b
F ext/fts5/test/fts5content.test 4234e0b11e003fe1e80472aa637f70464396fdd0
F ext/fts5/test/fts5corrupt.test b81ed310018ddffb34da7802f74018d94a2b3961
F ext/fts5/test/fts5content.test 8dc302fccdff834d946497e9d862750ea87d4517
F ext/fts5/test/fts5corrupt.test 78eb076867e750a013b46b3bc06065870bc93c22
F ext/fts5/test/fts5ea.test 04695560a444fcc00c3c4f27783bdcfbf71f030c
F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
F ext/fts5/test/fts5fault1.test f9bafb61b40061ad19b61d15003c5faeea4a57b5
F ext/fts5/test/fts5fault1.test fbd8612889234849ff041f5b36f8e390feeed46e
F ext/fts5/test/fts5near.test 3f9f64e16cac82725d03d4e04c661090f0b3b947
F ext/fts5/test/fts5optimize.test 0028c90a7817d3e576d1148fc8dff17d89054e54
F ext/fts5/test/fts5porter.test 50322599823cb8080a99f0ec0c39f7d0c12bcb5e
F ext/fts5/test/fts5prefix.test 4610dfba4460d92f23a8014874a46493f1be77b5
F ext/fts5/test/fts5rebuild.test 2a5e98205393487b4a732c8290999af7c0b907b4
F ext/fts5/test/fts5rowid.test db482328fe9bf78bb6a09f2dbf055e2caeaac00a
F ext/fts5/test/fts5rowid.test a1b2a6d76648c734c1aab11ee1a619067e8d90e6
F ext/fts5/test/fts5tokenizer.test b34ae592db66f6e89546d791ce1f905ba0b3395c
F ext/fts5/test/fts5unicode.test 79b3e34eb29ce4929628aa514a40cb467fdabe4d
F ext/fts5/test/fts5unicode2.test 64a5267fd6082fcb46439892ebd0cbaa5c38acee
@ -1283,7 +1283,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 939b7a5de25e064bdf08e03864c35ab718da6f6f
R 7096f8b96e0f85e1680222eb9ee6721b
P 51444f67c0cc58a3023eb1cd78e7cf889da6c80f
R bde0099a6ffad2afb653ac6add38295f
U dan
Z 0515045012673cdccd49d82241057133
Z 8b04510bfa3b18ba6ca879f4b4c9a36e

View File

@ -1 +1 @@
51444f67c0cc58a3023eb1cd78e7cf889da6c80f
5206ca6005bfa9dfc7346d4b89430c9748d32c10