/ Check-in [49be646c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a bug preventing FTS from correctly processing bracket tokens that are immediately preceded by characters that are neither whitespace or token characters.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 49be646cd981f8ff0434cf90d2748afa30260017
User & Date: dan 2013-11-04 08:56:22
Context
2013-11-07
16:08
Add support for WITHOUT ROWID tables. This change also includes (1) standardization of the error message returned from run-time constraint errors, (2) improved EXPLAIN comments, (3) the SQLITE_ENABLE_EXPLAIN_COMMENTS option, (4) the SQLITE_ENABLE_MODULE_COMMENTS option, and (5) a bug fix (see [573cc27427]) in the handling of REPLACE on the rowid when secondary indices use FAIL or IGNORE. check-in: c80e229d user: drh tags: trunk
2013-11-04
08:56
Fix a bug preventing FTS from correctly processing bracket tokens that are immediately preceded by characters that are neither whitespace or token characters. check-in: 49be646c user: dan tags: trunk
2013-11-02
11:34
A pair of sqlite3_analyzer bug fixes: (1) quote strings in the SQL at the end of the output. (2) Fix test_stat.c so that it no longer misses some overflow pages on internal index pages. check-in: 42a11e74 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_expr.c.

   151    151         }
   152    152       }
   153    153     }
   154    154     *ppCsr = pCsr;
   155    155     return rc;
   156    156   }
   157    157   
          158  +/*
          159  +** Function getNextNode(), which is called by fts3ExprParse(), may itself
          160  +** call fts3ExprParse(). So this forward declaration is required.
          161  +*/
          162  +static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
   158    163   
   159    164   /*
   160    165   ** Extract the next token from buffer z (length n) using the tokenizer
   161    166   ** and other information (column names etc.) in pParse. Create an Fts3Expr
   162    167   ** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
   163    168   ** single token and set *ppExpr to point to it. If the end of the buffer is
   164    169   ** reached before a token is found, set *ppExpr to zero. It is the
................................................................................
   185    190     rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
   186    191     if( rc==SQLITE_OK ){
   187    192       const char *zToken;
   188    193       int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
   189    194       int nByte;                               /* total space to allocate */
   190    195   
   191    196       rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
   192         -    if( rc==SQLITE_OK ){
          197  +
          198  +    if( (rc==SQLITE_OK || rc==SQLITE_DONE) && sqlite3_fts3_enable_parentheses ){
          199  +      int i;
          200  +      if( rc==SQLITE_DONE ) iStart = n;
          201  +      for(i=0; i<iStart; i++){
          202  +        if( z[i]=='(' ){
          203  +          pParse->nNest++;
          204  +          rc = fts3ExprParse(pParse, &z[i+1], n-i-1, &pRet, &nConsumed);
          205  +          if( rc==SQLITE_OK && !pRet ){
          206  +            rc = SQLITE_DONE;
          207  +          }
          208  +          nConsumed = (int)(i + 1 + nConsumed);
          209  +          break;
          210  +        }
          211  +
          212  +        if( z[i]==')' ){
          213  +          rc = SQLITE_DONE;
          214  +          pParse->nNest--;
          215  +          nConsumed = i+1;
          216  +          break;
          217  +        }
          218  +      }
          219  +    }
          220  +
          221  +    if( nConsumed==0 && rc==SQLITE_OK ){
   193    222         nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
   194    223         pRet = (Fts3Expr *)fts3MallocZero(nByte);
   195    224         if( !pRet ){
   196    225           rc = SQLITE_NOMEM;
   197    226         }else{
   198    227           pRet->eType = FTSQUERY_PHRASE;
   199    228           pRet->pPhrase = (Fts3Phrase *)&pRet[1];
................................................................................
   365    394     }
   366    395     sqlite3_free(zTemp);
   367    396     sqlite3_free(p);
   368    397     *ppExpr = 0;
   369    398     return SQLITE_NOMEM;
   370    399   }
   371    400   
   372         -/*
   373         -** Function getNextNode(), which is called by fts3ExprParse(), may itself
   374         -** call fts3ExprParse(). So this forward declaration is required.
   375         -*/
   376         -static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
   377         -
   378    401   /*
   379    402   ** The output variable *ppExpr is populated with an allocated Fts3Expr 
   380    403   ** structure, or set to 0 if the end of the input buffer is reached.
   381    404   **
   382    405   ** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM
   383    406   ** if a malloc failure occurs, or SQLITE_ERROR if a parse error is encountered.
   384    407   ** If SQLITE_ERROR is returned, pContext is populated with an error message.
................................................................................
   467    490   
   468    491         /* Turns out that wasn't a keyword after all. This happens if the
   469    492         ** user has supplied a token such as "ORacle". Continue.
   470    493         */
   471    494       }
   472    495     }
   473    496   
   474         -  /* Check for an open bracket. */
   475         -  if( sqlite3_fts3_enable_parentheses ){
   476         -    if( *zInput=='(' ){
   477         -      int nConsumed;
   478         -      pParse->nNest++;
   479         -      rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
   480         -      if( rc==SQLITE_OK && !*ppExpr ){
   481         -        rc = SQLITE_DONE;
   482         -      }
   483         -      *pnConsumed = (int)((zInput - z) + 1 + nConsumed);
   484         -      return rc;
   485         -    }
   486         -  
   487         -    /* Check for a close bracket. */
   488         -    if( *zInput==')' ){
   489         -      pParse->nNest--;
   490         -      *pnConsumed = (int)((zInput - z) + 1);
   491         -      return SQLITE_DONE;
   492         -    }
   493         -  }
   494         -
   495    497     /* See if we are dealing with a quoted phrase. If this is the case, then
   496    498     ** search for the closing quote and pass the whole string to getNextString()
   497    499     ** for processing. This is easy to do, as fts3 has no syntax for escaping
   498    500     ** a quote character embedded in a string.
   499    501     */
   500    502     if( *zInput=='"' ){
   501    503       for(ii=1; ii<nInput && zInput[ii]!='"'; ii++);

Changes to test/fts3expr.test.

    24     24   }
    25     25   
    26     26   set sqlite_fts3_enable_parentheses 1
    27     27   
    28     28   proc test_fts3expr {expr} {
    29     29     db one {SELECT fts3_exprtest('simple', $expr, 'a', 'b', 'c')}
    30     30   }
           31  +
    31     32   do_test fts3expr-1.0 {
    32     33     test_fts3expr "abcd"
    33     34   } {PHRASE 3 0 abcd}
    34     35   do_test fts3expr-1.1 {
    35     36     test_fts3expr " tag "
    36     37   } {PHRASE 3 0 tag}
    37     38   
................................................................................
   491    492       CREATE VIRTUAL TABLE test USING fts3 (keyword);
   492    493       INSERT INTO test VALUES ('abc');
   493    494       SELECT * FROM test WHERE keyword MATCH '""';
   494    495     }
   495    496   } {}
   496    497   
   497    498   
          499  +do_test fts3expr-8.0 { test_fts3expr "(blah)" } {PHRASE 3 0 blah}
          500  +do_test fts3expr-8.1 { test_fts3expr "(blah.)" } {PHRASE 3 0 blah}
          501  +do_test fts3expr-8.2 { test_fts3expr "(blah,)" } {PHRASE 3 0 blah}
          502  +do_test fts3expr-8.3 { test_fts3expr "(blah!)" } {PHRASE 3 0 blah}
          503  +do_test fts3expr-8.4 { test_fts3expr "(blah-)" } {PHRASE 3 0 blah}
          504  +
          505  +do_test fts3expr-8.5 { test_fts3expr "((blah.))" } {PHRASE 3 0 blah}
          506  +do_test fts3expr-8.6 { test_fts3expr "(((blah,)))" } {PHRASE 3 0 blah}
          507  +do_test fts3expr-8.7 { test_fts3expr "((((blah!))))" } {PHRASE 3 0 blah}
          508  +
          509  +do_test fts3expr-8.8 { test_fts3expr "(,(blah-),)" } {PHRASE 3 0 blah}
          510  +
   498    511   set sqlite_fts3_enable_parentheses 0
   499    512   finish_test