Beispiel #1
0
        static int tclvarBestIndex(sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo)
        {
            int ii;

            for (ii = 0; ii < pIdxInfo.nConstraint; ii++)
            {
                sqlite3_index_constraint pCons = pIdxInfo.aConstraint[ii];
                if (pCons.iColumn == 0 && pCons.usable &&
                    pCons.op == SQLITE_INDEX_CONSTRAINT_EQ)
                {
                    sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
                    pUsage           = pIdxInfo.aConstraintUsage[ii];
                    pUsage.omit      = false;
                    pUsage.argvIndex = 1;
                    return(SQLITE_OK);
                }
            }

            for (ii = 0; ii < pIdxInfo.nConstraint; ii++)
            {
                sqlite3_index_constraint pCons = pIdxInfo.aConstraint[ii];
                if (pCons.iColumn == 0 && pCons.usable &&
                    pCons.op == SQLITE_INDEX_CONSTRAINT_MATCH)
                {
                    sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
                    pUsage           = pIdxInfo.aConstraintUsage[ii];
                    pUsage.omit      = true;
                    pUsage.argvIndex = 1;
                    return(SQLITE_OK);
                }
            }

            return(SQLITE_OK);
        }
Beispiel #2
0
    /*
    ** The echo module implements the subset of query constraints and sort
    ** orders that may take advantage of SQLite indices on the underlying
    ** real table. For example, if the real table is declared as:
    **
    **     CREATE TABLE real(a, b, c);
    **     CREATE INDEX real_index ON real(b);
    **
    ** then the echo module handles WHERE or ORDER BY clauses that refer
    ** to the column "b", but not "a" or "c". If a multi-column index is
    ** present, only its left most column is considered. 
    **
    ** This xBestIndex method encodes the proposed search strategy as
    ** an SQL query on the real table underlying the virtual echo module 
    ** table and stores the query in sqlite3_index_info.idxStr. The SQL
    ** statement is of the form:
    **
    **   SELECT rowid, * FROM <real-table> ?<where-clause>? ?<order-by-clause>?
    **
    ** where the <where-clause> and <order-by-clause> are determined
    ** by the contents of the structure pointed to by the pIdxInfo argument.
    */
    static int echoBestIndex( sqlite3_vtab vtab, ref sqlite3_index_info pIdxInfo )
    {
      int ii;
      string zQuery = "";
      string zNew;
      int nArg = 0;
      string zSep = "WHERE";
      echo_vtab pVtab = (echo_vtab)vtab;
      sqlite3_stmt pStmt = null;
      Tcl_Interp interp = pVtab.interp;

      int nRow = 0;
      int useIdx = 0;
      int rc = SQLITE_OK;
      int useCost = 0;
      double cost = 0;
      int isIgnoreUsable = 0;
      if ( TCL.Tcl_GetVar( interp, "echo_module_ignore_usable", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString() != "" )
      {
        isIgnoreUsable = 1;
      }

      if ( simulateVtabError( pVtab, "xBestIndex" ) != 0 )
      {
        return SQLITE_ERROR;
      }

      /* Determine the number of rows in the table and store this value in local
      ** variable nRow. The 'estimated-cost' of the scan will be the number of
      ** rows in the table for a linear scan, or the log (base 2) of the 
      ** number of rows if the proposed scan uses an index.  
      */
      if ( TCL.Tcl_GetVar( interp, "echo_module_cost", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString() != "" )
      {
        Double.TryParse( TCL.Tcl_GetVar( interp, "echo_module_cost", (TCL.VarFlag)TCL.TCL_GLOBAL_ONLY ).ToString(), out cost );
        useCost = 1;
      }
      else
      {
        zQuery = sqlite3_mprintf( "SELECT count() FROM %Q", pVtab.zTableName );
        //if ( null == zQuery )
        //{
        //  return SQLITE_NOMEM;
        //}
        rc = sqlite3_prepare( pVtab.db, zQuery, -1, ref pStmt, 0 );
        //sqlite3_free(zQuery);
        if ( rc != SQLITE_OK )
        {
          return rc;
        }
        sqlite3_step( pStmt );
        nRow = sqlite3_column_int( pStmt, 0 );
        rc = sqlite3_finalize( pStmt );
        if ( rc != SQLITE_OK )
        {
          return rc;
        }
      }

      zQuery = sqlite3_mprintf( "SELECT rowid, * FROM %Q", pVtab.zTableName );
      //if ( null == zQuery )
      //{
      //  return SQLITE_NOMEM;
      //}
      for ( ii = 0; ii < pIdxInfo.nConstraint; ii++ )
      {
        sqlite3_index_constraint pConstraint;
        sqlite3_index_constraint_usage pUsage;
        int iCol;

        pConstraint = pIdxInfo.aConstraint[ii];
        pUsage = pIdxInfo.aConstraintUsage[ii];

        if ( 0 == isIgnoreUsable && !pConstraint.usable )
          continue;

        iCol = pConstraint.iColumn;
        if (  iCol < 0 || pVtab.aIndex[iCol] != 0 )
        {
          string zCol;
          string zOp = "";
          useIdx = 1;
          if ( iCol >= 0 )
          {
            zCol = pVtab.aCol[iCol];
          }
          else
          {
            zCol = "rowid";
          }
          switch ( pConstraint.op )
          {
            case SQLITE_INDEX_CONSTRAINT_EQ:
              zOp = "=";
              break;
            case SQLITE_INDEX_CONSTRAINT_LT:
              zOp = "<";
              break;
            case SQLITE_INDEX_CONSTRAINT_GT:
              zOp = ">";
              break;
            case SQLITE_INDEX_CONSTRAINT_LE:
              zOp = "<=";
              break;
            case SQLITE_INDEX_CONSTRAINT_GE:
              zOp = ">=";
              break;
            case SQLITE_INDEX_CONSTRAINT_MATCH:
              zOp = "LIKE";
              break;
          }
          if ( zOp[0] == 'L' )
          {
            zNew = sqlite3_mprintf( " %s %s LIKE (SELECT '%%'||?||'%%')",
                                   zSep, zCol );
          }
          else
          {
            zNew = sqlite3_mprintf( " %s %s %s ?", zSep, zCol, zOp );
          }
          string_concat( ref zQuery, zNew, 1, ref rc );

          zSep = "AND";
          pUsage.argvIndex = ++nArg;
          pUsage.omit = true;
        }
      }

      /* If there is only one term in the ORDER BY clause, and it is
      ** on a column that this virtual table has an index for, then consume 
      ** the ORDER BY clause.
      */
      if ( pIdxInfo.nOrderBy == 1 && ( pIdxInfo.aOrderBy[0].iColumn < 0 || pVtab.aIndex[pIdxInfo.aOrderBy[0].iColumn] != 0 ) )
      {
        int iCol = pIdxInfo.aOrderBy[0].iColumn;
        string zCol;
        string zDir = pIdxInfo.aOrderBy[0].desc ? "DESC" : "ASC";
        if ( iCol >= 0 )
        {
          zCol = pVtab.aCol[iCol];
        }
        else
        {
          zCol = "rowid";
        }
        zNew = sqlite3_mprintf( " ORDER BY %s %s", zCol, zDir );
        string_concat( ref zQuery, zNew, 1, ref rc );
        pIdxInfo.orderByConsumed = true;
      }

      appendToEchoModule( pVtab.interp, "xBestIndex" );
      ;
      appendToEchoModule( pVtab.interp, zQuery );

      if ( null == zQuery )
      {
        return rc;
      }
      pIdxInfo.idxNum = hashString( zQuery );
      pIdxInfo.idxStr = zQuery;
      pIdxInfo.needToFreeIdxStr = 1;
      if ( useCost != 0 )
      {
        pIdxInfo.estimatedCost = cost;
      }
      else if ( useIdx != 0 )
      {
        /* Approximation of log2(nRow). */
        for ( ii = 0; ii < ( sizeof( int ) * 8 ); ii++ )
        {
          if ( ( nRow & ( 1 << ii ) ) != 0 )
          {
            pIdxInfo.estimatedCost = (double)ii;
          }
        }
      }
      else
      {
        pIdxInfo.estimatedCost = (double)nRow;
      }
      return rc;
    }
 /*
 ** Analyse the WHERE condition.
 */
 static int intarrayBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
 {
   return SQLITE_OK;
 }
Beispiel #4
0
 /*
 ** Analyse the WHERE condition.
 */
 static int schemaBestIndex(sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo)
 {
     return(SQLITE_OK);
 }
static int tclvarBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
{
  int ii;

  for(ii=0; ii<pIdxInfo.nConstraint; ii++){
    sqlite3_index_constraint  pCons = pIdxInfo.aConstraint[ii];
    if( pCons.iColumn==0 && pCons.usable
           && pCons.op==SQLITE_INDEX_CONSTRAINT_EQ ){
      sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
      pUsage = pIdxInfo.aConstraintUsage[ii];
      pUsage.omit = false;
      pUsage.argvIndex = 1;
      return SQLITE_OK;
    }
  }

  for(ii=0; ii<pIdxInfo.nConstraint; ii++){
    sqlite3_index_constraint pCons = pIdxInfo.aConstraint[ii];
    if( pCons.iColumn==0 && pCons.usable
           && pCons.op==SQLITE_INDEX_CONSTRAINT_MATCH ){
      sqlite3_index_constraint_usage pUsage = new sqlite3_index_constraint_usage();
      pUsage = pIdxInfo.aConstraintUsage[ii];
      pUsage.omit = true;
      pUsage.argvIndex = 1;
      return SQLITE_OK;
    }
  }

  return SQLITE_OK;
}
 /*
 ** Search for terms of these forms:
 **
 **  (1)  value > $value
 **  (2)  value >= $value
 **  (4)  value < $value
 **  (8)  value <= $value
 **
 ** idxNum is an ORed combination of 1 or 2 with 4 or 8.
 */
 static int wholenumberBestIndex(
 sqlite3_vtab vtab,
 ref sqlite3_index_info pIdxInfo
 )
 {
   int i;
   int idxNum = 0;
   int argvIdx = 1;
   int ltIdx = -1;
   int gtIdx = -1;
   sqlite3_index_constraint pConstraint;
   //pConstraint = pIdxInfo.aConstraint;
   for ( i = 0; i < pIdxInfo.nConstraint; i++ )//, pConstraint++)
   {
     pConstraint = pIdxInfo.aConstraint[i];
     if ( pConstraint.usable == false )
       continue;
     if ( ( idxNum & 3 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GT )
     {
       idxNum |= 1;
       ltIdx = i;
     }
     if ( ( idxNum & 3 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GE )
     {
       idxNum |= 2;
       ltIdx = i;
     }
     if ( ( idxNum & 12 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LT )
     {
       idxNum |= 4;
       gtIdx = i;
     }
     if ( ( idxNum & 12 ) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LE )
     {
       idxNum |= 8;
       gtIdx = i;
     }
   }
   pIdxInfo.idxNum = idxNum;
   if ( ltIdx >= 0 )
   {
     pIdxInfo.aConstraintUsage[ltIdx].argvIndex = argvIdx++;
     pIdxInfo.aConstraintUsage[ltIdx].omit = true;
   }
   if ( gtIdx >= 0 )
   {
     pIdxInfo.aConstraintUsage[gtIdx].argvIndex = argvIdx;
     pIdxInfo.aConstraintUsage[gtIdx].omit = true;
   }
   if ( pIdxInfo.nOrderBy == 1
   && pIdxInfo.aOrderBy[0].desc == false
   )
   {
     pIdxInfo.orderByConsumed = true;
   }
   pIdxInfo.estimatedCost = (double)1;
   return SQLITE_OK;
 }
Beispiel #7
0
        /*
        ** Search for terms of these forms:
        **
        **  (1)  value > $value
        **  (2)  value >= $value
        **  (4)  value < $value
        **  (8)  value <= $value
        **
        ** idxNum is an ORed combination of 1 or 2 with 4 or 8.
        */
        static int wholenumberBestIndex(
            sqlite3_vtab vtab,
            ref sqlite3_index_info pIdxInfo
            )
        {
            int i;
            int idxNum  = 0;
            int argvIdx = 1;
            int ltIdx   = -1;
            int gtIdx   = -1;
            sqlite3_index_constraint pConstraint;

            //pConstraint = pIdxInfo.aConstraint;
            for (i = 0; i < pIdxInfo.nConstraint; i++)//, pConstraint++)
            {
                pConstraint = pIdxInfo.aConstraint[i];
                if (pConstraint.usable == false)
                {
                    continue;
                }
                if ((idxNum & 3) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GT)
                {
                    idxNum |= 1;
                    ltIdx   = i;
                }
                if ((idxNum & 3) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_GE)
                {
                    idxNum |= 2;
                    ltIdx   = i;
                }
                if ((idxNum & 12) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LT)
                {
                    idxNum |= 4;
                    gtIdx   = i;
                }
                if ((idxNum & 12) == 0 && pConstraint.op == SQLITE_INDEX_CONSTRAINT_LE)
                {
                    idxNum |= 8;
                    gtIdx   = i;
                }
            }
            pIdxInfo.idxNum = idxNum;
            if (ltIdx >= 0)
            {
                pIdxInfo.aConstraintUsage[ltIdx].argvIndex = argvIdx++;
                pIdxInfo.aConstraintUsage[ltIdx].omit      = true;
            }
            if (gtIdx >= 0)
            {
                pIdxInfo.aConstraintUsage[gtIdx].argvIndex = argvIdx;
                pIdxInfo.aConstraintUsage[gtIdx].omit      = true;
            }
            if (pIdxInfo.nOrderBy == 1 &&
                pIdxInfo.aOrderBy[0].desc == false
                )
            {
                pIdxInfo.orderByConsumed = true;
            }
            pIdxInfo.estimatedCost = (double)1;
            return(SQLITE_OK);
        }
Beispiel #8
0
    /*
    ** There is no "best-index". This virtual table always does a linear
    ** scan of the binary VFS log file.
    */
    static int statBestIndex( sqlite3_vtab tab, ref sqlite3_index_info pIdxInfo )
    {

      /* Records are always returned in ascending order of (name, path). 
      ** If this will satisfy the client, set the orderByConsumed flag so that 
      ** SQLite does not do an external sort.
      */
      if ( ( pIdxInfo.nOrderBy == 1
         && pIdxInfo.aOrderBy[0].iColumn == 0
         && pIdxInfo.aOrderBy[0].desc == false
         ) ||
          ( pIdxInfo.nOrderBy == 2
         && pIdxInfo.aOrderBy[0].iColumn == 0
         && pIdxInfo.aOrderBy[0].desc == false
         && pIdxInfo.aOrderBy[1].iColumn == 1
         && pIdxInfo.aOrderBy[1].desc == false
         )
      )
      {
        pIdxInfo.orderByConsumed = true;
      }

      pIdxInfo.estimatedCost = 10.0;
      return SQLITE_OK;
    }