/ Check-in [f480b1fe]
Login
Overview
Comment:Improve the error message issued when an FTS query exceeds the maximum allowable tree depth.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:f480b1fe6012f36c59cd0525efdc6df74143ccd0
User & Date: dan 2013-04-29 18:07:37
Context
2013-04-30
14:06
Make sure extra parentheses around subqueries in the FROM clause are harmless. Ticket [28c6e830f239ea5]. check-in: 1c795692 user: drh tags: trunk
2013-04-29
18:07
Improve the error message issued when an FTS query exceeds the maximum allowable tree depth. check-in: f480b1fe user: dan tags: trunk
17:12
Fix an off-by-one in the code for limiting the depth of FTS expression trees. check-in: 72ac7318 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

  2971   2971       if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
  2972   2972         return SQLITE_NOMEM;
  2973   2973       }
  2974   2974   
  2975   2975       pCsr->iLangid = 0;
  2976   2976       if( nVal==2 ) pCsr->iLangid = sqlite3_value_int(apVal[1]);
  2977   2977   
         2978  +    assert( p->base.zErrMsg==0 );
  2978   2979       rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
  2979         -        p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
         2980  +        p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr, 
         2981  +        &p->base.zErrMsg
  2980   2982       );
  2981   2983       if( rc!=SQLITE_OK ){
  2982         -      if( rc==SQLITE_ERROR ){
  2983         -        static const char *zErr = "malformed MATCH expression: [%s]";
  2984         -        p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
  2985         -      }
  2986   2984         return rc;
  2987   2985       }
  2988   2986   
  2989   2987       rc = sqlite3Fts3ReadLock(p);
  2990   2988       if( rc!=SQLITE_OK ) return rc;
  2991   2989   
  2992   2990       rc = fts3EvalStart(pCsr);

Changes to ext/fts3/fts3Int.h.

   520    520   void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
   521    521     const char *, const char *, int, int
   522    522   );
   523    523   void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
   524    524   
   525    525   /* fts3_expr.c */
   526    526   int sqlite3Fts3ExprParse(sqlite3_tokenizer *, int,
   527         -  char **, int, int, int, const char *, int, Fts3Expr **
          527  +  char **, int, int, int, const char *, int, Fts3Expr **, char **
   528    528   );
   529    529   void sqlite3Fts3ExprFree(Fts3Expr *);
   530    530   #ifdef SQLITE_TEST
   531    531   int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
   532    532   int sqlite3Fts3InitTerm(sqlite3 *db);
   533    533   #endif
   534    534   

Changes to ext/fts3/fts3_expr.c.

   752    752   ** Return SQLITE_ERROR if the maximum depth of the expression tree passed 
   753    753   ** as the only argument is more than nMaxDepth.
   754    754   */
   755    755   static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
   756    756     int rc = SQLITE_OK;
   757    757     if( p ){
   758    758       if( nMaxDepth<0 ){ 
   759         -      rc = SQLITE_ERROR;
          759  +      rc = SQLITE_TOOBIG;
   760    760       }else{
   761    761         rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
   762    762         if( rc==SQLITE_OK ){
   763    763           rc = fts3ExprCheckDepth(p->pRight, nMaxDepth-1);
   764    764         }
   765    765       }
   766    766     }
................................................................................
   837    837               pFree = pFree->pParent;
   838    838               p->pParent = 0;
   839    839               apLeaf[iLvl] = 0;
   840    840             }
   841    841           }
   842    842           if( p ){
   843    843             sqlite3Fts3ExprFree(p);
   844         -          rc = SQLITE_ERROR;
          844  +          rc = SQLITE_TOOBIG;
   845    845             break;
   846    846           }
   847    847   
   848    848           /* If that was the last leaf node, break out of the loop */
   849    849           if( pParent==0 ) break;
   850    850   
   851    851           /* Set $p to point to the next leaf in the tree of eType nodes */
................................................................................
   992    992     sqlite3_tokenizer *pTokenizer,      /* Tokenizer module */
   993    993     int iLangid,                        /* Language id for tokenizer */
   994    994     char **azCol,                       /* Array of column names for fts3 table */
   995    995     int bFts4,                          /* True to allow FTS4-only syntax */
   996    996     int nCol,                           /* Number of entries in azCol[] */
   997    997     int iDefaultCol,                    /* Default column to query */
   998    998     const char *z, int n,               /* Text of MATCH query */
   999         -  Fts3Expr **ppExpr                   /* OUT: Parsed query structure */
          999  +  Fts3Expr **ppExpr,                  /* OUT: Parsed query structure */
         1000  +  char **pzErr                        /* OUT: Error message (sqlite3_malloc) */
  1000   1001   ){
  1001   1002     static const int MAX_EXPR_DEPTH = 12;
  1002   1003     int rc = fts3ExprParseUnbalanced(
  1003   1004         pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
  1004   1005     );
  1005   1006     
  1006   1007     /* Rebalance the expression. And check that its depth does not exceed
................................................................................
  1007   1008     ** MAX_EXPR_DEPTH.  */
  1008   1009     if( rc==SQLITE_OK && *ppExpr ){
  1009   1010       rc = fts3ExprBalance(ppExpr, MAX_EXPR_DEPTH);
  1010   1011       if( rc==SQLITE_OK ){
  1011   1012         rc = fts3ExprCheckDepth(*ppExpr, MAX_EXPR_DEPTH);
  1012   1013       }
  1013   1014     }
         1015  +
  1014   1016     if( rc!=SQLITE_OK ){
  1015   1017       sqlite3Fts3ExprFree(*ppExpr);
  1016   1018       *ppExpr = 0;
         1019  +    if( rc==SQLITE_TOOBIG ){
         1020  +      *pzErr = sqlite3_mprintf(
         1021  +          "FTS expression tree is too large (maximum depth %d)", MAX_EXPR_DEPTH
         1022  +      );
         1023  +      rc = SQLITE_ERROR;
         1024  +    }else if( rc==SQLITE_ERROR ){
         1025  +      *pzErr = sqlite3_mprintf("malformed MATCH expression: [%s]", z);
         1026  +    }
  1017   1027     }
  1018   1028   
  1019   1029     return rc;
  1020   1030   }
  1021   1031   
  1022   1032   /*
  1023   1033   ** Free a single node of an expression tree.
................................................................................
  1212   1222       goto exprtest_out;
  1213   1223     }
  1214   1224     for(ii=0; ii<nCol; ii++){
  1215   1225       azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
  1216   1226     }
  1217   1227   
  1218   1228     if( sqlite3_user_data(context) ){
         1229  +    char *zDummy = 0;
  1219   1230       rc = sqlite3Fts3ExprParse(
  1220         -        pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
         1231  +        pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr, &zDummy
  1221   1232       );
  1222   1233       assert( rc==SQLITE_OK || pExpr==0 );
         1234  +    sqlite3_free(zDummy);
  1223   1235     }else{
  1224   1236       rc = fts3ExprParseUnbalanced(
  1225   1237           pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
  1226   1238       );
  1227   1239     }
  1228   1240   
  1229   1241     if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){