]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Reorganize some of the fts5 expression parsing code. Improve test coverage of the...
authordan <dan@noemail.net>
Sat, 2 May 2015 20:35:24 +0000 (20:35 +0000)
committerdan <dan@noemail.net>
Sat, 2 May 2015 20:35:24 +0000 (20:35 +0000)
FossilOrigin-Name: c4456dc5f5f8f45f04e3bbae53b6bcc209fc27d5

ext/fts5/fts5Int.h
ext/fts5/fts5_buffer.c
ext/fts5/fts5_config.c
ext/fts5/fts5_expr.c
ext/fts5/test/fts5ea.test
ext/fts5/test/fts5fault4.test
manifest
manifest.uuid

index 34190bdec15581ef2503864027eedfa73540cb18..07c3a767b22182088c2d81621fe7645ca1049082 100644 (file)
@@ -228,6 +228,7 @@ int sqlite3Fts5PoslistNext64(
 
 /* Malloc utility */
 void *sqlite3Fts5MallocZero(int *pRc, int nByte);
+char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn);
 
 /*
 ** End of interface to code in fts5_buffer.c.
index 26304f68aa80c0fc7f64e28eb3786028d654d15a..dbe51fafc459244b8b1468504e13d95a2efc294a 100644 (file)
@@ -239,5 +239,30 @@ void *sqlite3Fts5MallocZero(int *pRc, int nByte){
   }
   return pRet;
 }
+
+/*
+** Return a nul-terminated copy of the string indicated by pIn. If nIn
+** is non-negative, then it is the length of the string in bytes. Otherwise,
+** the length of the string is determined using strlen().
+**
+** It is the responsibility of the caller to eventually free the returned
+** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. 
+*/
+char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
+  char *zRet = 0;
+  if( *pRc==SQLITE_OK ){
+    if( nIn<0 ){
+      nIn = strlen(pIn);
+    }
+    zRet = (char*)sqlite3_malloc(nIn+1);
+    if( zRet ){
+      memcpy(zRet, pIn, nIn);
+      zRet[nIn] = '\0';
+    }else{
+      *pRc = SQLITE_NOMEM;
+    }
+  }
+  return zRet;
+}
 #endif /* SQLITE_ENABLE_FTS5 */
 
index eae18dce27add2ca8e8fc0b380a6edb7ada51f07..1b29351ec276f0b8b75768c5c27413cbbd548d97 100644 (file)
@@ -203,21 +203,6 @@ void sqlite3Fts5Dequote(char *z){
   }
 }
 
-/*
-** Duplicate the string passed as the only argument into a buffer allocated
-** by sqlite3_malloc().
-**
-** Return 0 if an OOM error is encountered.
-*/
-static char *fts5Strdup(int *pRc, const char *z){
-  char *pRet = 0;
-  if( *pRc==SQLITE_OK ){
-    pRet = sqlite3_mprintf("%s", z);
-    if( pRet==0 ) *pRc = SQLITE_NOMEM;
-  }
-  return pRet;
-}
-
 /*
 ** Argument z points to a nul-terminated string containing an SQL identifier.
 ** This function returns a copy of the identifier enclosed in backtick 
@@ -368,7 +353,7 @@ static int fts5ConfigParseSpecial(
       *pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
       rc = SQLITE_ERROR;
     }else{
-      pConfig->zContentRowid = fts5Strdup(&rc, zArg);
+      pConfig->zContentRowid = sqlite3Fts5Strndup(&rc, zArg, -1);
     }
     return rc;
   }
@@ -526,8 +511,8 @@ int sqlite3Fts5ConfigParse(
   nByte = nArg * (sizeof(char*) + sizeof(u8));
   pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
   pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
-  pRet->zDb = fts5Strdup(&rc, azArg[1]);
-  pRet->zName = fts5Strdup(&rc, azArg[2]);
+  pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
+  pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
   if( rc==SQLITE_OK && sqlite3_stricmp(pRet->zName, FTS5_RANK_NAME)==0 ){
     *pzErr = sqlite3_mprintf("reserved fts5 table name: %s", pRet->zName);
     rc = SQLITE_ERROR;
@@ -591,7 +576,7 @@ int sqlite3Fts5ConfigParse(
     }
   }
   if( rc==SQLITE_OK && pRet->zContentRowid==0 ){
-    pRet->zContentRowid = fts5Strdup(&rc, "rowid");
+    pRet->zContentRowid = sqlite3Fts5Strndup(&rc, "rowid", -1);
   }
 
   /* Formulate the zContentExprlist text */
index 79dfec566753936eb3ee8e06a51172bce22a57d2..570331bfb119835f4c08192edc761b67d8360f36 100644 (file)
@@ -231,33 +231,6 @@ int sqlite3Fts5ExprNew(
   return sParse.rc;
 }
 
-static char *fts5ExprStrdup(int *pRc, const char *zIn){
-  char *zRet = 0;
-  if( *pRc==SQLITE_OK ){
-    int nByte = strlen(zIn) + 1;
-    zRet = sqlite3_malloc(nByte);
-    if( zRet ){
-      memcpy(zRet, zIn, nByte);
-    }else{
-      *pRc = SQLITE_NOMEM;
-    }
-  }
-  return zRet;
-}
-
-static void *fts5ExprMalloc(int *pRc, int nByte){
-  void *pRet = 0;
-  if( *pRc==SQLITE_OK ){
-    pRet = sqlite3_malloc(nByte);
-    if( pRet ){
-      memset(pRet, 0, nByte);
-    }else{
-      *pRc = SQLITE_NOMEM;
-    }
-  }
-  return pRet;
-}
-
 /*
 ** Create a new FTS5 expression by cloning phrase iPhrase of the
 ** expression passed as the second argument.
@@ -274,7 +247,7 @@ int sqlite3Fts5ExprPhraseExpr(
   Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
 
   pOrig = pExpr->apExprPhrase[iPhrase];
-  pCopy = (Fts5ExprPhrase*)fts5ExprMalloc(&rc, 
+  pCopy = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(&rc, 
       sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * pOrig->nTerm
   );
   if( pCopy ){
@@ -283,15 +256,17 @@ int sqlite3Fts5ExprPhraseExpr(
     Fts5ExprNode *pNode;
     Fts5ExprNearset *pNear;
 
-    pNew = (Fts5Expr*)fts5ExprMalloc(&rc, sizeof(Fts5Expr));
-    apPhrase = (Fts5ExprPhrase**)fts5ExprMalloc(&rc, sizeof(Fts5ExprPhrase*));
-    pNode = (Fts5ExprNode*)fts5ExprMalloc(&rc, sizeof(Fts5ExprNode));
-    pNear = (Fts5ExprNearset*)fts5ExprMalloc(&rc, 
+    pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+    apPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
+        sizeof(Fts5ExprPhrase*)
+    );
+    pNode = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprNode));
+    pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc, 
         sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*)
     );
 
     for(i=0; i<pOrig->nTerm; i++){
-      pCopy->aTerm[i].zTerm = fts5ExprStrdup(&rc, pOrig->aTerm[i].zTerm);
+      pCopy->aTerm[i].zTerm = sqlite3Fts5Strndup(&rc, pOrig->aTerm[i].zTerm,-1);
       pCopy->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
     }
 
@@ -576,29 +551,29 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){
 }
 
 /*
-** Advance each term iterator in each phrase in pNear. If any reach EOF, 
-** set output variable *pbEof to true before returning.
+** Advance the first term iterator in the first phrase of pNear. Set output
+** variable *pbEof to true if it reaches EOF or if an error occurs.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** occurs.
 */
-static int fts5ExprNearAdvanceAll(
+static int fts5ExprNearAdvanceFirst(
   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
-  Fts5ExprNearset *pNear,         /* Near object to advance iterators of */
-  int *pbEof                      /* OUT: Set to true if phrase at EOF */
+  Fts5ExprNode *pNode,            /* FTS5_STRING node */
+  int bFromValid,
+  i64 iFrom 
 ){
-  int i, j;                       /* Phrase and token index, respectively */
+  Fts5IndexIter *pIter = pNode->pNear->apPhrase[0]->aTerm[0].pIter;
+  int rc;
 
-  for(i=0; i<pNear->nPhrase; i++){
-    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
-    for(j=0; j<pPhrase->nTerm; j++){
-      Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
-      int rc = sqlite3Fts5IterNext(pIter);
-      if( rc || sqlite3Fts5IterEof(pIter) ){
-        *pbEof = 1;
-        return rc;
-      }
-    }
+  if( bFromValid ){
+    rc = sqlite3Fts5IterNextFrom(pIter, iFrom);
+  }else{
+    rc = sqlite3Fts5IterNext(pIter);
   }
 
-  return SQLITE_OK;
+  pNode->bEof = (rc || sqlite3Fts5IterEof(pIter));
+  return rc;
 }
 
 /*
@@ -649,9 +624,7 @@ static int fts5ExprAdvanceto(
 */
 static int fts5ExprNearNextRowidMatch(
   Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
-  Fts5ExprNode *pNode,
-  int bFromValid,
-  i64 iFrom
+  Fts5ExprNode *pNode
 ){
   Fts5ExprNearset *pNear = pNode->pNear;
   int rc = SQLITE_OK;
@@ -664,10 +637,6 @@ static int fts5ExprNearNextRowidMatch(
   ** 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->bDesc==0) ){
-    assert( pExpr->bDesc || iFrom>=iLast );
-    iLast = iFrom;
-  }
 
   do {
     bMatch = 1;
@@ -707,9 +676,7 @@ static int fts5ExprNearNextRowidMatch(
 */
 static int fts5ExprNearNextMatch(
   Fts5Expr *pExpr,                /* Expression that pNear is a part of */
-  Fts5ExprNode *pNode,            /* The "NEAR" node (FTS5_STRING) */
-  int bFromValid,
-  i64 iFrom
+  Fts5ExprNode *pNode             /* The "NEAR" node (FTS5_STRING) */
 ){
   int rc = SQLITE_OK;
   Fts5ExprNearset *pNear = pNode->pNear;
@@ -717,7 +684,7 @@ static int fts5ExprNearNextMatch(
     int i;
 
     /* Advance the iterators until they all point to the same rowid */
-    rc = fts5ExprNearNextRowidMatch(pExpr, pNode, bFromValid, iFrom);
+    rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
     if( rc!=SQLITE_OK || pNode->bEof ) break;
 
     /* Check that each phrase in the nearset matches the current row.
@@ -748,7 +715,7 @@ static int fts5ExprNearNextMatch(
     /* If control flows to here, then the current rowid is not a match.
     ** Advance all term iterators in all phrases to the next rowid. */
     if( rc==SQLITE_OK ){
-      rc = fts5ExprNearAdvanceAll(pExpr, pNear, &pNode->bEof);
+      rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0);
     }
     if( pNode->bEof || rc!=SQLITE_OK ) break;
   }
@@ -797,7 +764,23 @@ static int fts5ExprNearInitAll(
 }
 
 /* fts5ExprNodeNext() calls fts5ExprNodeNextMatch(). And vice-versa. */
-static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*, int, i64);
+static int fts5ExprNodeNextMatch(Fts5Expr*, Fts5ExprNode*);
+
+
+static int fts5RowidCmp(
+  Fts5Expr *pExpr,
+  i64 iLhs,
+  i64 iRhs
+){
+  assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
+  if( pExpr->bDesc==0 ){
+    if( iLhs<iRhs ) return -1;
+    return (iLhs > iRhs);
+  }else{
+    if( iLhs>iRhs ) return -1;
+    return (iLhs < iRhs);
+  }
+}
 
 /*
 ** Compare the values currently indicated by the two nodes as follows:
@@ -818,13 +801,7 @@ static int fts5NodeCompare(
 ){
   if( p2->bEof ) return -1;
   if( p1->bEof ) return +1;
-  if( pExpr->bDesc==0 ){
-    if( p1->iRowid<p2->iRowid ) return -1;
-    return (p1->iRowid > p2->iRowid);
-  }else{
-    if( p1->iRowid>p2->iRowid ) return -1;
-    return (p1->iRowid < p2->iRowid);
-  }
+  return fts5RowidCmp(pExpr, p1->iRowid, p2->iRowid);
 }
 
 /*
@@ -845,7 +822,7 @@ static int fts5ExprNodeNext(
   if( pNode->bEof==0 ){
     switch( pNode->eType ){
       case FTS5_STRING: {
-        rc = fts5ExprNearAdvanceAll(pExpr, pNode->pNear, &pNode->bEof);
+        rc = fts5ExprNearAdvanceFirst(pExpr, pNode, bFromValid, iFrom);
         break;
       };
 
@@ -863,13 +840,14 @@ static int fts5ExprNodeNext(
         Fts5ExprNode *p2 = pNode->pRight;
         int cmp = fts5NodeCompare(pExpr, p1, p2);
 
-        if( cmp==0 ){
+        if( cmp<=0 || (bFromValid && fts5RowidCmp(pExpr,p1->iRowid,iFrom)<0) ){
           rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
+        }
+
+        if( cmp>=0 || (bFromValid && fts5RowidCmp(pExpr,p2->iRowid,iFrom)<0) ){
           if( rc==SQLITE_OK ){
             rc = fts5ExprNodeNext(pExpr, p2, bFromValid, iFrom);
           }
-        }else{
-          rc = fts5ExprNodeNext(pExpr, (cmp < 0) ? p1 : p2, bFromValid, iFrom);
         }
 
         break;
@@ -882,10 +860,22 @@ static int fts5ExprNodeNext(
     }
 
     if( rc==SQLITE_OK ){
-      rc = fts5ExprNodeNextMatch(pExpr, pNode, bFromValid, iFrom);
+      rc = fts5ExprNodeNextMatch(pExpr, pNode);
     }
   }
 
+  /* Assert that if bFromValid was true, either:
+  **
+  **   a) an error occurred, or
+  **   b) the node is now at EOF, or
+  **   c) the node is now at or past rowid iFrom.
+  */
+  assert( bFromValid==0 
+      || rc!=SQLITE_OK                                                  /* a */
+      || pNode->bEof                                                    /* b */
+      || pNode->iRowid==iFrom || pExpr->bDesc==(pNode->iRowid<iFrom)    /* c */
+  );
+
   return rc;
 }
 
@@ -898,20 +888,20 @@ static void fts5ExprSetEof(Fts5ExprNode *pNode){
 }
 
 /*
-**
+** If pNode currently points to a match, this function returns SQLITE_OK
+** without modifying it. Otherwise, pNode is advanced until it does point
+** to a match or EOF is reached.
 */
 static int fts5ExprNodeNextMatch(
-  Fts5Expr *pExpr, 
-  Fts5ExprNode *pNode,
-  int bFromValid,
-  i64 iFrom
+  Fts5Expr *pExpr,                /* Expression of which pNode is a part */
+  Fts5ExprNode *pNode             /* Expression node to test */
 ){
   int rc = SQLITE_OK;
   if( pNode->bEof==0 ){
     switch( pNode->eType ){
 
       case FTS5_STRING: {
-        rc = fts5ExprNearNextMatch(pExpr, pNode, bFromValid, iFrom);
+        rc = fts5ExprNearNextMatch(pExpr, pNode);
         break;
       }
 
@@ -921,17 +911,14 @@ static int fts5ExprNodeNextMatch(
 
         while( p1->bEof==0 && p2->bEof==0 && p2->iRowid!=p1->iRowid ){
           Fts5ExprNode *pAdv;
+          i64 iFrom;
           assert( pExpr->bDesc==0 || pExpr->bDesc==1 );
           if( pExpr->bDesc==(p1->iRowid > p2->iRowid) ){
             pAdv = p1;
-            if( bFromValid==0 || pExpr->bDesc==(p2->iRowid < iFrom) ){
-              iFrom = p2->iRowid;
-            }
+            iFrom = p2->iRowid;
           }else{
             pAdv = p2;
-            if( bFromValid==0 || pExpr->bDesc==(p1->iRowid < iFrom) ){
-              iFrom = p1->iRowid;
-            }
+            iFrom = p1->iRowid;
           }
           rc = fts5ExprNodeNext(pExpr, pAdv, 1, iFrom);
           if( rc!=SQLITE_OK ) break;
@@ -955,13 +942,16 @@ static int fts5ExprNodeNextMatch(
       default: assert( pNode->eType==FTS5_NOT ); {
         Fts5ExprNode *p1 = pNode->pLeft;
         Fts5ExprNode *p2 = pNode->pRight;
-        while( rc==SQLITE_OK ){
-          int cmp;
-          while( rc==SQLITE_OK && (cmp = fts5NodeCompare(pExpr, p1, p2))>0 ){
-            rc = fts5ExprNodeNext(pExpr, p2, bFromValid, iFrom);
+
+        while( rc==SQLITE_OK && p1->bEof==0 ){
+          int cmp = fts5NodeCompare(pExpr, p1, p2);
+          if( cmp>0 ){
+            rc = fts5ExprNodeNext(pExpr, p2, 1, p1->iRowid);
+            cmp = fts5NodeCompare(pExpr, p1, p2);
           }
-          if( rc || cmp ) break;
-          rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
+          assert( rc!=SQLITE_OK || cmp<=0 );
+          if( rc || cmp<0 ) break;
+          rc = fts5ExprNodeNext(pExpr, p1, 0, 0);
         }
         pNode->bEof = p1->bEof;
         pNode->iRowid = p1->iRowid;
@@ -991,7 +981,7 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
 
     /* Attempt to advance to the first match */
     if( rc==SQLITE_OK && pNode->bEof==0 ){
-      rc = fts5ExprNearNextMatch(pExpr, pNode, 0, 0);
+      rc = fts5ExprNearNextMatch(pExpr, pNode);
     }
 
   }else{
@@ -1000,7 +990,7 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
       rc = fts5ExprNodeFirst(pExpr, pNode->pRight);
     }
     if( rc==SQLITE_OK ){
-      rc = fts5ExprNodeNextMatch(pExpr, pNode, 0, 0);
+      rc = fts5ExprNodeNextMatch(pExpr, pNode);
     }
   }
   return rc;
@@ -1047,31 +1037,9 @@ i64 sqlite3Fts5ExprRowid(Fts5Expr *p){
   return p->pRoot->iRowid;
 }
 
-/*
-** Argument pIn points to a buffer of nIn bytes. This function allocates
-** and returns a new buffer populated with a copy of (pIn/nIn) with a 
-** nul-terminator byte appended to it.
-**
-** It is the responsibility of the caller to eventually free the returned
-** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned. 
-*/
-static char *fts5Strndup(int *pRc, const char *pIn, int nIn){
-  char *zRet = 0;
-  if( *pRc==SQLITE_OK ){
-    zRet = (char*)sqlite3_malloc(nIn+1);
-    if( zRet ){
-      memcpy(zRet, pIn, nIn);
-      zRet[nIn] = '\0';
-    }else{
-      *pRc = SQLITE_NOMEM;
-    }
-  }
-  return zRet;
-}
-
 static int fts5ParseStringFromToken(Fts5Token *pToken, char **pz){
   int rc = SQLITE_OK;
-  *pz = fts5Strndup(&rc, pToken->p, pToken->n);
+  *pz = sqlite3Fts5Strndup(&rc, pToken->p, pToken->n);
   return rc;
 }
 
@@ -1123,7 +1091,7 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
         pRet->iCol = -1;
       }
     }else if( (pNear->nPhrase % SZALLOC)==0 ){
-      int nNew = pRet->nPhrase + SZALLOC;
+      int nNew = pNear->nPhrase + SZALLOC;
       int nByte = sizeof(Fts5ExprNearset) + nNew * sizeof(Fts5ExprPhrase*);
 
       pRet = (Fts5ExprNearset*)sqlite3_realloc(pNear, nByte);
@@ -1181,7 +1149,7 @@ static int fts5ParseTokenize(
 
   pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
   memset(pTerm, 0, sizeof(Fts5ExprTerm));
-  pTerm->zTerm = fts5Strndup(&rc, pToken, nToken);
+  pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
 
   return rc;
 }
@@ -1272,12 +1240,10 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
 ** in the pParse object.
 */
 void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
-  if( pParse->rc==SQLITE_OK ){
-    if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
-      sqlite3Fts5ParseError(
-          pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
-      );
-    }
+  if( pTok->n!=4 || memcmp("NEAR", pTok->p, 4) ){
+    sqlite3Fts5ParseError(
+        pParse, "fts5: syntax error near \"%.*s\"", pTok->n, pTok->p
+    );
   }
 }
 
@@ -1310,23 +1276,25 @@ void sqlite3Fts5ParseSetColumn(
   Fts5ExprNearset *pNear, 
   Fts5Token *p
 ){
-  char *z = 0;
-  int rc = fts5ParseStringFromToken(p, &z);
-  if( rc==SQLITE_OK ){
-    Fts5Config *pConfig = pParse->pConfig;
-    int i;
-    for(i=0; i<pConfig->nCol; i++){
-      if( 0==sqlite3_stricmp(pConfig->azCol[i], z) ){
-        pNear->iCol = i;
-        break;
+  if( pParse->rc==SQLITE_OK ){
+    char *z = 0;
+    int rc = fts5ParseStringFromToken(p, &z);
+    if( rc==SQLITE_OK ){
+      Fts5Config *pConfig = pParse->pConfig;
+      int i;
+      for(i=0; i<pConfig->nCol; i++){
+        if( 0==sqlite3_stricmp(pConfig->azCol[i], z) ){
+          pNear->iCol = i;
+          break;
+        }
       }
+      if( i==pConfig->nCol ){
+        sqlite3Fts5ParseError(pParse, "no such column: %s", z);
+      }
+      sqlite3_free(z);
+    }else{
+      pParse->rc = rc;
     }
-    if( i==pConfig->nCol ){
-      sqlite3Fts5ParseError(pParse, "no such column: %s", z);
-    }
-    sqlite3_free(z);
-  }else{
-    pParse->rc = rc;
   }
 }
 
index 7b58d8cd8fc5efd5cd87ea3306ba1c21134770b0..1248edea0b908a0f5790a0afeea37b8ae0e93b52 100644 (file)
@@ -66,11 +66,15 @@ foreach {tn expr err} {
   3 {abc OR AND}                   {fts5: syntax error near "AND"}
   4 {(a OR b) abc}                 {fts5: syntax error near "abc"}
   5 {NEaR (a b)}                   {fts5: syntax error near "NEaR"}
-  6 {(a OR b) NOT c)}              {fts5: syntax error near ")"}
-  7 {nosuch: a nosuch2: b}         {no such column: nosuch}
-  8 {addr: a nosuch2: b}           {no such column: nosuch2}
-  9 {NOT}                          {fts5: syntax error near "NOT"}
-  10 {a AND "abc}                  {unterminated string}
+  6 {NEa (a b)}                    {fts5: syntax error near "NEa"}
+  7 {(a OR b) NOT c)}              {fts5: syntax error near ")"}
+  8 {nosuch: a nosuch2: b}         {no such column: nosuch}
+  9 {addr: a nosuch2: b}           {no such column: nosuch2}
+  10 {NOT}                          {fts5: syntax error near "NOT"}
+  11 {a AND "abc}                  {unterminated string}
+
+  12 {NEAR(a b, xyz)}              {expected integer, got "xyz"}
+  13 {NEAR(a b, // )}              {expected integer, got "//"}
 } {
   do_catchsql_test 3.$tn {SELECT fts5_expr($expr, 'name', 'addr')} [list 1 $err]
 }
index 8e6c827ad3e4bd2cd2a36e62244a2f777d70cbc6..943d331db86b0d543f40ca17ffa5a5619d1e9016 100644 (file)
@@ -201,6 +201,8 @@ do_faultsim_test 6.2 -faults oom-t* -body {
   faultsim_test_result {0 {0 2 7}} {1 SQLITE_NOMEM}
 }
 
+}
+
 #-------------------------------------------------------------------------
 # OOM error when querying for a phrase with many tokens.
 #
@@ -218,6 +220,10 @@ do_execsql_test 7.0 {
   INSERT INTO tt VALUES('e a e b e e', 'd c c f f f');  -- 9
   INSERT INTO tt VALUES('f a g g c c', 'e g d g c e');  -- 10
   INSERT INTO tt VALUES('c d b a e f', 'f g e h e e');  -- 11
+
+  CREATE VIRTUAL TABLE tt2 USING fts5(o);
+  INSERT INTO tt2(rowid, o) SELECT rowid, x||' '||y FROM tt;
+  INSERT INTO tt2(rowid, o) VALUES(12, 'a b c d e f g h i j k l');
 }
 
 do_faultsim_test 7.2 -faults oom-* -body {
@@ -232,6 +238,22 @@ do_faultsim_test 7.3 -faults oom-* -body {
   faultsim_test_result {0 11} {1 SQLITE_NOMEM}
 }
 
+do_faultsim_test 7.4 -faults oom-t* -body {
+  db eval { SELECT rowid FROM tt2 WHERE tt2 MATCH '"g c f c e f e e a f"' }
+} -test {
+  faultsim_test_result {0 8} {1 SQLITE_NOMEM}
+}
+
+do_faultsim_test 7.5 -faults oom-* -body {
+  db eval {SELECT rowid FROM tt2 WHERE tt2 MATCH 'NEAR(a b c d e f g h i j k)'}
+} -test {
+  faultsim_test_result {0 12} {1 SQLITE_NOMEM}
+}
+
+do_faultsim_test 7.6 -faults oom-* -body {
+  db eval {SELECT rowid FROM tt WHERE tt MATCH 'y: "c c"'}
+} -test {
+  faultsim_test_result {0 {1 9}} {1 SQLITE_NOMEM}
 }
 
 #-------------------------------------------------------------------------
@@ -261,6 +283,27 @@ do_faultsim_test 8.2 -faults oom-t* -body {
 }
 
 
+#-------------------------------------------------------------------------
+# Fault in NOT query.
+#
+reset_db
+do_execsql_test 9.0 {
+  CREATE VIRTUAL TABLE tt USING fts5(x);
+  INSERT INTO tt(tt, rank) VALUES('pgsz', 32);
+  BEGIN;
+    WITH ii(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM ii WHERE i<200)
+      INSERT INTO tt(rowid, x) 
+      SELECT i, CASE WHEN (i%50)==0 THEN 'a a a a a a' ELSE 'a x a x a x' END 
+      FROM ii;
+  COMMIT;
+}
+
+do_faultsim_test 9.1 -faults oom-* -body {
+  db eval { SELECT rowid FROM tt WHERE tt MATCH 'a NOT x' }
+} -test {
+  faultsim_test_result {0 {50 100 150 200}} {1 SQLITE_NOMEM}
+}
+
 
 
 finish_test
index 92d1a1bb517952611e002181eddffd45c24bcb1d..53ddbec52dada1222f65f1690fe4901250316385 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Further\simprovements\sto\stest\scoverage\sof\sfts5\scode.
-D 2015-05-01T20:38:57.153
+C Reorganize\ssome\sof\sthe\sfts5\sexpression\sparsing\scode.\sImprove\stest\scoverage\sof\sthe\ssame.
+D 2015-05-02T20:35:24.467
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 31b38b9da2e4b36f54a013bd71a5c3f6e45ca78f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -106,11 +106,11 @@ F ext/fts3/unicode/mkunicode.tcl 159c1194da0bc72f51b3c2eb71022568006dc5ad
 F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
 F ext/fts5/fts5.c 3a0a73bcfbcb7e65ccda099cfb8fd268d2480c7e
 F ext/fts5/fts5.h 24a2cc35b5e76eec57b37ba48c12d9d2cb522b3a
-F ext/fts5/fts5Int.h 2e0a1a6b77e1e014b7e9b1479ca686ff79930457
+F ext/fts5/fts5Int.h 05e97ffb2911e8c8cfcb8bdb009e17347c24eb2d
 F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971
-F ext/fts5/fts5_buffer.c 8c8cfe7f09ca2767ab53ea883f9a0af0edb6bbae
-F ext/fts5/fts5_config.c ecbbd5163758a958106867051892e0dfecf68b5c
-F ext/fts5/fts5_expr.c e2005ba7823f4ac51d46a8e5aaa1ff66c701b32e
+F ext/fts5/fts5_buffer.c 70b971e13503566f1e257941c60817ba0920a16b
+F ext/fts5/fts5_config.c 4e0de8bea4746a7560740b9dcf8be4dced68ef4f
+F ext/fts5/fts5_expr.c f49d68411dc72cb66f2b55cc109dbf3dce368eef
 F ext/fts5/fts5_hash.c 29d8b0668727863cc1f1efa65efe4dd78635b016
 F ext/fts5/fts5_index.c de588982b0237b1605d6c37afd115b34c95c3da1
 F ext/fts5/fts5_storage.c ef60fc9dcc4e274f9589165e26833173c273ae18
@@ -140,12 +140,12 @@ F ext/fts5/test/fts5corrupt.test 138aecc75c36c3dac9259c7f57c5bc3d009255f8
 F ext/fts5/test/fts5corrupt2.test 494111fd4f2dab36499cf97718eaba1f7c11e9d0
 F ext/fts5/test/fts5dlidx.test 748a84ceb74a4154725096a26dfa854260b0182f
 F ext/fts5/test/fts5doclist.test 635b80ac785627841a59c583bac702b55d49fdc5
-F ext/fts5/test/fts5ea.test 7cc498993c16849bb866dbdfb008d91a29f9870b
+F ext/fts5/test/fts5ea.test f4d35cd2776dab9358206f7d88a67ea187fdec22
 F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
 F ext/fts5/test/fts5fault1.test ed71717a479bef32d05f02d9c48691011d160d4d
 F ext/fts5/test/fts5fault2.test 26c3d70648f691e2cc9391e14bbc11a973656383
 F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
-F ext/fts5/test/fts5fault4.test 4090af395d8d3342c0a0b27349dd71eb7cc6262d
+F ext/fts5/test/fts5fault4.test 09728cadb4897c97cea092edb9c431d9ec25b88b
 F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d
 F ext/fts5/test/fts5hash.test adb7b0442cc1c77c507f07e16d11490486e75dfa
 F ext/fts5/test/fts5merge.test 453a0717881aa7784885217b2040f3f275caff03
@@ -1315,7 +1315,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 add4f4681c648dcbecaa68d08f7b2f4e6d63003c
-R 58de859125935eeaf7ecede3ffbb5a07
+P d4331943dff259380c4025bb740d8aba6972d351
+R 5651f6663bbd8efe3d630621e3f4b900
 U dan
-Z fc00d731e9356a3f17b66c35cad599ad
+Z 822e7611ba479003f18b45bbb7ca820a
index ee6ce26d115f940b8a1c7cdd8bc02c1e34c0f5c5..ddc1ccf8f362c9e3f449943f7d14b4ca0d41632a 100644 (file)
@@ -1 +1 @@
-d4331943dff259380c4025bb740d8aba6972d351
\ No newline at end of file
+c4456dc5f5f8f45f04e3bbae53b6bcc209fc27d5
\ No newline at end of file