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); }
/* ** 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; }
/* ** 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; }
/* ** 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); }
/* ** 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; }