/ Check-in [18142fdb]
Login

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

Overview
Comment:http://www.sqlite.org/cvstrac/tktview?tn=2046

The virtual table interface allows for a cursor to field multiple xFilter() calls. For instance, if a join is done with a virtual table, there could be a call for each row which potentially matches. Unfortunately, fulltextFilter() assumes that it has a fresh cursor, and overwrites a prepared statement and a malloc'ed pointer, resulting in unfinalized statements and a memory leak.

This change hacks the code to manually clean up offending items in fulltextFilter(), emphasis on "hacks", since it's a fragile fix insofar as future additions to fulltext_cursor could continue to have the problem. (CVS 3521)

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 18142fdb6d1f5bfdbb1155274502b9a602885fcb
User & Date: shess 2006-11-29 05:17:28
Context
2006-11-29
20:53
Added the speed1.test script (CVS 3522) check-in: 30355dfb user: drh tags: trunk
05:17
http://www.sqlite.org/cvstrac/tktview?tn=2046

The virtual table interface allows for a cursor to field multiple xFilter() calls. For instance, if a join is done with a virtual table, there could be a call for each row which potentially matches. Unfortunately, fulltextFilter() assumes that it has a fresh cursor, and overwrites a prepared statement and a malloc'ed pointer, resulting in unfinalized statements and a memory leak.

This change hacks the code to manually clean up offending items in fulltextFilter(), emphasis on "hacks", since it's a fragile fix insofar as future additions to fulltext_cursor could continue to have the problem. (CVS 3521) check-in: 18142fdb user: shess tags: trunk

01:02
Delta-encode terms in interior nodes. While experiments have shown that this is of marginal utility when encoding terms resulting from regular English text, it turns out to be very useful when encoding inputs with very large terms. (CVS 3520) check-in: c8151a99 user: shess tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts1/fts1.c.

  2036   2036     clearTableSpec(&spec);
  2037   2037     return rc;
  2038   2038   }
  2039   2039   
  2040   2040   /* Decide how to handle an SQL query. */
  2041   2041   static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
  2042   2042     int i;
         2043  +  TRACE(("FTS1 BestIndex\n"));
  2043   2044   
  2044   2045     for(i=0; i<pInfo->nConstraint; ++i){
  2045   2046       const struct sqlite3_index_constraint *pConstraint;
  2046   2047       pConstraint = &pInfo->aConstraint[i];
  2047   2048       if( pConstraint->usable ) {
  2048   2049         if( pConstraint->iColumn==-1 &&
  2049   2050             pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
  2050   2051           pInfo->idxNum = QUERY_ROWID;      /* lookup by rowid */
         2052  +        TRACE(("FTS1 QUERY_ROWID\n"));
  2051   2053         } else if( pConstraint->iColumn>=0 &&
  2052   2054                    pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
  2053   2055           /* full-text search */
  2054   2056           pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn;
         2057  +        TRACE(("FTS1 QUERY_FULLTEXT %d\n", pConstraint->iColumn));
  2055   2058         } else continue;
  2056   2059   
  2057   2060         pInfo->aConstraintUsage[i].argvIndex = 1;
  2058   2061         pInfo->aConstraintUsage[i].omit = 1;
  2059   2062   
  2060   2063         /* An arbitrary value for now.
  2061   2064          * TODO: Perhaps rowid matches should be considered cheaper than
................................................................................
  2062   2065          * full-text searches. */
  2063   2066         pInfo->estimatedCost = 1.0;   
  2064   2067   
  2065   2068         return SQLITE_OK;
  2066   2069       }
  2067   2070     }
  2068   2071     pInfo->idxNum = QUERY_GENERIC;
  2069         -  TRACE(("FTS1 BestIndex\n"));
  2070   2072     return SQLITE_OK;
  2071   2073   }
  2072   2074   
  2073   2075   static int fulltextDisconnect(sqlite3_vtab *pVTab){
  2074   2076     TRACE(("FTS1 Disconnect %p\n", pVTab));
  2075   2077     fulltext_vtab_destroy((fulltext_vtab *)pVTab);
  2076   2078     return SQLITE_OK;
................................................................................
  2813   2815   ** If idxNum==QUERY_ROWID then do a rowid lookup for a single entry
  2814   2816   ** in the %_content table.
  2815   2817   **
  2816   2818   ** If idxNum>=QUERY_FULLTEXT then use the full text index.  The
  2817   2819   ** column on the left-hand side of the MATCH operator is column
  2818   2820   ** number idxNum-QUERY_FULLTEXT, 0 indexed.  argv[0] is the right-hand
  2819   2821   ** side of the MATCH operator.
         2822  +*/
         2823  +/* TODO(shess) Upgrade the cursor initialization and destruction to
         2824  +** account for fulltextFilter() being called multiple times on the
         2825  +** same cursor.  The current solution is very fragile.  Apply fix to
         2826  +** fts2 as appropriate.
  2820   2827   */
  2821   2828   static int fulltextFilter(
  2822   2829     sqlite3_vtab_cursor *pCursor,     /* The cursor used for this query */
  2823   2830     int idxNum, const char *idxStr,   /* Which indexing scheme to use */
  2824   2831     int argc, sqlite3_value **argv    /* Arguments for the indexing scheme */
  2825   2832   ){
  2826   2833     fulltext_cursor *c = (fulltext_cursor *) pCursor;
................................................................................
  2828   2835     int rc;
  2829   2836     char *zSql;
  2830   2837   
  2831   2838     TRACE(("FTS1 Filter %p\n",pCursor));
  2832   2839   
  2833   2840     zSql = sqlite3_mprintf("select rowid, * from %%_content %s",
  2834   2841                             idxNum==QUERY_GENERIC ? "" : "where rowid=?");
         2842  +  sqlite3_finalize(c->pStmt);
  2835   2843     rc = sql_prepare(v->db, v->zName, &c->pStmt, zSql);
  2836   2844     sqlite3_free(zSql);
  2837         -  if( rc!=SQLITE_OK ) goto out;
         2845  +  if( rc!=SQLITE_OK ) return rc;
  2838   2846   
  2839   2847     c->iCursorType = idxNum;
  2840   2848     switch( idxNum ){
  2841   2849       case QUERY_GENERIC:
  2842   2850         break;
  2843   2851   
  2844   2852       case QUERY_ROWID:
  2845   2853         rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0]));
  2846         -      if( rc!=SQLITE_OK ) goto out;
         2854  +      if( rc!=SQLITE_OK ) return rc;
  2847   2855         break;
  2848   2856   
  2849   2857       default:   /* full-text search */
  2850   2858       {
  2851   2859         const char *zQuery = (const char *)sqlite3_value_text(argv[0]);
  2852   2860         DocList *pResult;
  2853   2861         assert( idxNum<=QUERY_FULLTEXT+v->nColumn);
  2854   2862         assert( argc==1 );
  2855   2863         queryClear(&c->q);
  2856   2864         rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &pResult, &c->q);
  2857         -      if( rc!=SQLITE_OK ) goto out;
         2865  +      if( rc!=SQLITE_OK ) return rc;
         2866  +      if( c->result.pDoclist!=NULL ) docListDelete(c->result.pDoclist);
  2858   2867         readerInit(&c->result, pResult);
  2859   2868         break;
  2860   2869       }
  2861   2870     }
  2862   2871   
  2863         -  rc = fulltextNext(pCursor);
  2864         -
  2865         -out:
  2866         -  return rc;
         2872  +  return fulltextNext(pCursor);
  2867   2873   }
  2868   2874   
  2869   2875   /* This is the xEof method of the virtual table.  The SQLite core
  2870   2876   ** calls this routine to find out if it has reached the end of
  2871   2877   ** a query's results set.
  2872   2878   */
  2873   2879   static int fulltextEof(sqlite3_vtab_cursor *pCursor){

Changes to ext/fts2/fts2.c.

  2609   2609     clearTableSpec(&spec);
  2610   2610     return rc;
  2611   2611   }
  2612   2612   
  2613   2613   /* Decide how to handle an SQL query. */
  2614   2614   static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
  2615   2615     int i;
         2616  +  TRACE(("FTS2 BestIndex\n"));
  2616   2617   
  2617   2618     for(i=0; i<pInfo->nConstraint; ++i){
  2618   2619       const struct sqlite3_index_constraint *pConstraint;
  2619   2620       pConstraint = &pInfo->aConstraint[i];
  2620   2621       if( pConstraint->usable ) {
  2621   2622         if( pConstraint->iColumn==-1 &&
  2622   2623             pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){
  2623   2624           pInfo->idxNum = QUERY_ROWID;      /* lookup by rowid */
         2625  +        TRACE(("FTS2 QUERY_ROWID\n"));
  2624   2626         } else if( pConstraint->iColumn>=0 &&
  2625   2627                    pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
  2626   2628           /* full-text search */
  2627   2629           pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn;
         2630  +        TRACE(("FTS2 QUERY_FULLTEXT %d\n", pConstraint->iColumn));
  2628   2631         } else continue;
  2629   2632   
  2630   2633         pInfo->aConstraintUsage[i].argvIndex = 1;
  2631   2634         pInfo->aConstraintUsage[i].omit = 1;
  2632   2635   
  2633   2636         /* An arbitrary value for now.
  2634   2637          * TODO: Perhaps rowid matches should be considered cheaper than
................................................................................
  2635   2638          * full-text searches. */
  2636   2639         pInfo->estimatedCost = 1.0;   
  2637   2640   
  2638   2641         return SQLITE_OK;
  2639   2642       }
  2640   2643     }
  2641   2644     pInfo->idxNum = QUERY_GENERIC;
  2642         -  TRACE(("FTS2 BestIndex\n"));
  2643   2645     return SQLITE_OK;
  2644   2646   }
  2645   2647   
  2646   2648   static int fulltextDisconnect(sqlite3_vtab *pVTab){
  2647   2649     TRACE(("FTS2 Disconnect %p\n", pVTab));
  2648   2650     fulltext_vtab_destroy((fulltext_vtab *)pVTab);
  2649   2651     return SQLITE_OK;
................................................................................
  3030   3032   */
  3031   3033   static int fulltextClose(sqlite3_vtab_cursor *pCursor){
  3032   3034     fulltext_cursor *c = (fulltext_cursor *) pCursor;
  3033   3035     TRACE(("FTS2 Close %p\n", c));
  3034   3036     sqlite3_finalize(c->pStmt);
  3035   3037     queryClear(&c->q);
  3036   3038     snippetClear(&c->snippet);
  3037         -  if( c->result.nData!=0 ){
  3038         -    dlrDestroy(&c->reader);
  3039         -    dataBufferDestroy(&c->result);
  3040         -  }
         3039  +  if( c->result.nData!=0 ) dlrDestroy(&c->reader);
         3040  +  dataBufferDestroy(&c->result);
  3041   3041     free(c);
  3042   3042     return SQLITE_OK;
  3043   3043   }
  3044   3044   
  3045   3045   static int fulltextNext(sqlite3_vtab_cursor *pCursor){
  3046   3046     fulltext_cursor *c = (fulltext_cursor *) pCursor;
  3047   3047     int rc;
................................................................................
  3395   3395   ** If idxNum==QUERY_ROWID then do a rowid lookup for a single entry
  3396   3396   ** in the %_content table.
  3397   3397   **
  3398   3398   ** If idxNum>=QUERY_FULLTEXT then use the full text index.  The
  3399   3399   ** column on the left-hand side of the MATCH operator is column
  3400   3400   ** number idxNum-QUERY_FULLTEXT, 0 indexed.  argv[0] is the right-hand
  3401   3401   ** side of the MATCH operator.
         3402  +*/
         3403  +/* TODO(shess) Upgrade the cursor initialization and destruction to
         3404  +** account for fulltextFilter() being called multiple times on the
         3405  +** same cursor.  The current solution is very fragile.  Apply fix to
         3406  +** fts2 as appropriate.
  3402   3407   */
  3403   3408   static int fulltextFilter(
  3404   3409     sqlite3_vtab_cursor *pCursor,     /* The cursor used for this query */
  3405   3410     int idxNum, const char *idxStr,   /* Which indexing scheme to use */
  3406   3411     int argc, sqlite3_value **argv    /* Arguments for the indexing scheme */
  3407   3412   ){
  3408   3413     fulltext_cursor *c = (fulltext_cursor *) pCursor;
................................................................................
  3410   3415     int rc;
  3411   3416     char *zSql;
  3412   3417   
  3413   3418     TRACE(("FTS2 Filter %p\n",pCursor));
  3414   3419   
  3415   3420     zSql = sqlite3_mprintf("select rowid, * from %%_content %s",
  3416   3421                             idxNum==QUERY_GENERIC ? "" : "where rowid=?");
         3422  +  sqlite3_finalize(c->pStmt);
  3417   3423     rc = sql_prepare(v->db, v->zName, &c->pStmt, zSql);
  3418   3424     sqlite3_free(zSql);
  3419         -  if( rc!=SQLITE_OK ) goto out;
         3425  +  if( rc!=SQLITE_OK ) return rc;
  3420   3426   
  3421   3427     c->iCursorType = idxNum;
  3422   3428     switch( idxNum ){
  3423   3429       case QUERY_GENERIC:
  3424   3430         break;
  3425   3431   
  3426   3432       case QUERY_ROWID:
  3427   3433         rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0]));
  3428         -      if( rc!=SQLITE_OK ) goto out;
         3434  +      if( rc!=SQLITE_OK ) return rc;
  3429   3435         break;
  3430   3436   
  3431   3437       default:   /* full-text search */
  3432   3438       {
  3433   3439         const char *zQuery = (const char *)sqlite3_value_text(argv[0]);
  3434   3440         assert( idxNum<=QUERY_FULLTEXT+v->nColumn);
  3435   3441         assert( argc==1 );
  3436   3442         queryClear(&c->q);
  3437         -      dataBufferInit(&c->result, 0);
         3443  +      if( c->result.nData!=0 ){
         3444  +        /* This case happens if the same cursor is used repeatedly. */
         3445  +        dlrDestroy(&c->reader);
         3446  +        dataBufferReset(&c->result);
         3447  +      }else{
         3448  +        dataBufferInit(&c->result, 0);
         3449  +      }
  3438   3450         rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q);
  3439   3451         if( rc!=SQLITE_OK ) return rc;
  3440   3452         if( c->result.nData!=0 ){
  3441   3453           dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData);
  3442   3454         }
  3443   3455         break;
  3444   3456       }
  3445   3457     }
  3446   3458   
  3447         -  rc = fulltextNext(pCursor);
  3448         -
  3449         -out:
  3450         -  return rc;
         3459  +  return fulltextNext(pCursor);
  3451   3460   }
  3452   3461   
  3453   3462   /* This is the xEof method of the virtual table.  The SQLite core
  3454   3463   ** calls this routine to find out if it has reached the end of
  3455   3464   ** a query's results set.
  3456   3465   */
  3457   3466   static int fulltextEof(sqlite3_vtab_cursor *pCursor){