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;
}
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;
pConfig->zDb, pConfig->zName, zRank, pConfig->zName,
(zRankArgs ? ", " : ""),
(zRankArgs ? zRankArgs : ""),
- bAsc ? "ASC" : "DESC"
+ bDesc ? "DESC" : "ASC"
);
if( zSql==0 ){
rc = SQLITE_NOMEM;
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);
}
){
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( 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;
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);
}
}
}
** 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.
*/
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 (*xTermDone)(void*)
);
+int sqlite3Fts5HashQuery(
+ Fts5Hash*, /* Hash table to query */
+ const char *pTerm, int nTerm, /* Query term */
+ Fts5Data **ppData /* OUT: Query result */
+);
/*
);
/*
-** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bAsc);
+** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
** rc==SQLITE_OK && 0==sqlite3Fts5ExprEof(pExpr);
** rc = sqlite3Fts5ExprNext(pExpr)
** ){
** 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*);
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 */
};
}
/*
-** 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
*/
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 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;
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;
}
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;
}
}
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( 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{
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;
}
}
/*
** 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;
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 */
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.
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 */
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;
}
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;
/* 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;
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;
return rc;
}
-
-
#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:
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;
};
struct Fts5DoclistIter {
- int bAsc;
+ int bDesc; /* True for DESC order, false for ASC */
u8 *a;
int n;
int i;
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
}
}
+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.
*/
}
/*
-** 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 */
}
}
-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.
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;
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);
iOff += fts5GetVarint32(&a[iOff], nPos);
iOff += nPos;
getVarint(&a[iOff], (u64*)&iDelta);
- pIter->iRowid += iDelta;
+ pIter->iRowid -= iDelta;
}else{
fts5SegIterReverseNewPage(p, pIter);
}
pIter->iLeafOffset += fts5GetVarint32(&a[iOff], nKeep);
}
}else{
- pIter->iRowid -= iDelta;
+ pIter->iRowid += iDelta;
}
}else{
iOff = 0;
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;
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);
}
}
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 ){
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.
}
}
+
+/*
+** 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.
**
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. */
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;
}
}
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;
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);
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);
}
*/
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);
*/
static void fts5MergePrefixLists(
Fts5Index *p, /* FTS5 backend object */
- int bAsc,
+ int bDesc,
Fts5Buffer *p1, /* First list to merge */
Fts5Buffer *p2 /* Second list to merge */
){
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);
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);
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 */
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++){
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);
}
for(i=0; i<nBuf; i++){
- fts5MergePrefixLists(p, bAsc, &doclist, &aBuf[i]);
+ fts5MergePrefixLists(p, bDesc, &doclist, &aBuf[i]);
fts5BufferFree(&aBuf[i]);
}
fts5MultiIterFree(p, p1);
fts5BufferFree(&doclist);
}else{
pIter->pDoclist = pDoclist;
- fts5DoclistIterInit(&doclist, bAsc, pIter->pDoclist);
+ fts5DoclistIterInit(&doclist, bDesc, pIter->pDoclist);
}
}
);
}
}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);
}
}
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 );
}
i64 iDelta;
iOff += sqlite3GetVarint(&a[iOff], (u64*)&iDelta);
if( iDelta==0 ) return iOff;
- iDocid -= iDelta;
+ iDocid += iDelta;
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " rowid=%lld", iDocid);
}
}
}
fts5DecodePoslist(&rc, &s, &a[4], iOff-4);
-
assert( iRowidOff==0 || iOff==iRowidOff );
if( iRowidOff ){
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], n-iOff);
}
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}
#-------------------------------------------------------------------------
#
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;
}
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 {
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]
}
#-------------------------------------------------------------------------
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
}
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
}
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
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
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:
# 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]
# Test phrase queries.
#
foreach {tn phrase} {
+ 8 "c"
+
1 "o"
2 "b q"
3 "e a e"
}
#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
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
}
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 {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*}
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 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}}
}
#-------------------------------------------------------------------------
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 {
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 {
-- '[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]}
}
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]
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} {
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}}
}
#-------------------------------------------------------------------------
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 {
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} {
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
}
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;
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
#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
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
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
}
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 {
-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
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
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
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
-51444f67c0cc58a3023eb1cd78e7cf889da6c80f
\ No newline at end of file
+5206ca6005bfa9dfc7346d4b89430c9748d32c10
\ No newline at end of file