]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Have fts5 store rowids in ascending order. Query speed is virtually the same regardle...
authordan <dan@noemail.net>
Sat, 24 Jan 2015 19:57:03 +0000 (19:57 +0000)
committerdan <dan@noemail.net>
Sat, 24 Jan 2015 19:57:03 +0000 (19:57 +0000)
FossilOrigin-Name: 5206ca6005bfa9dfc7346d4b89430c9748d32c10

18 files changed:
ext/fts5/fts5.c
ext/fts5/fts5Int.h
ext/fts5/fts5_expr.c
ext/fts5/fts5_hash.c
ext/fts5/fts5_index.c
ext/fts5/test/fts5aa.test
ext/fts5/test/fts5ab.test
ext/fts5/test/fts5ac.test
ext/fts5/test/fts5ad.test
ext/fts5/test/fts5ae.test
ext/fts5/test/fts5ak.test
ext/fts5/test/fts5al.test
ext/fts5/test/fts5content.test
ext/fts5/test/fts5corrupt.test
ext/fts5/test/fts5fault1.test
ext/fts5/test/fts5rowid.test
manifest
manifest.uuid

index c61598e47706b1f19f8528862934c8e1ba6a03ab..d748a8b40f64f8e32f91959e25a9f1ca8c623c74 100644 (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);
             }
           }
         }
index 728b6461a13e83118f60cbebb5367e9f68bb3077..50003632d1743c1ab6d4e7ee1065f058aa6ef095 100644 (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*);
index 71f8b48069e206e609c059b9428290d5bca33b6e..bbf8c68acb5e4da9f74054c4583d3533b3783c2c 100644 (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;
index 61eed74be47d48d1d6512344e9d4545c9c43806c..41b2eb774a17ffd0405010bd3e60684e10696dae 100644 (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;
 }
 
-
-
index 0cb2c2ee31c5b42fc05ee96b04396ed19989a4bc..602046a3020f0e4bd6287b03cb66f5d55733c52e 100644 (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);
index 450539e889760567f9debddf54ba1795db807230..cd3de2655b2916ce9c8a725dc8acbd7da260fe27 100644 (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;
index 79ebc7eaa52236b68f67d3cf6b61901dfc9e1148..d68240901e91339382e1923eca61150dc28d4d3a 100644 (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
 
index 76f663ac5fdc6aab5232f0a0722a589adb616a62..713e70dcd484d0281f783cbebcaa9f94bab17188 100644 (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
index 9bc694f784fea9f4519cb842d53ee966dfcb5906..89a5078816fe4896605097b8d4c7e5147590656e 100644 (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*} 
index f327bc920702f24bbe2bf01dfb5d8a041362a150..c9c3fcce30effa3ff47c04a29cf98bb9cbce5467 100644 (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}}
 }
 
 #-------------------------------------------------------------------------
index 756ae0a8981367e182a6f6086c79850813feeec7..4eb28324c940ee98d3b329a2fc24369be3d9bc47 100644 (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]}
 }
 
 
index 31d51713affe9ccdd8be13a8b4ba03dc7e09a7d7..36402d6f6b871b8993ec76a40bf91609af2c083f 100644 (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 
 }
 
 
index 948a4308b6bae65a682efa2b6e46d20de9fbd7e9..145fa4b6a9418d6ac63de1b70f3aeb86e5d15bb9 100644 (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
index 052563f779342af5630dfd8b09b210a80db99ec9..57473afe6575fa71eb5089cdcc13ea29988c2bac 100644 (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
 
index 68aed258ec9a17df233b7512e677b7cc3b0a5082..838bf3cc4b82ef3656b6af237940ec38da0b54be 100644 (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
   }
index c33c9adea3de85d31f290ceee8952600da1ffa26..7ffd2977bfcb20d023c9ca404c6468a9f832fcd8 100644 (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 {
index 9fdcf2e5e54caf3e6f9e11be70b3c4060adf3052..d15cc908b2df337e194d1eaefed5d08aff38b782 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index 324db551dab6930974dbfd8e442898c438015f05..fb905f204889bab265cd823ce81517ecc6971ddd 100644 (file)
@@ -1 +1 @@
-51444f67c0cc58a3023eb1cd78e7cf889da6c80f
\ No newline at end of file
+5206ca6005bfa9dfc7346d4b89430c9748d32c10
\ No newline at end of file