static int xBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) { auto *pVtab = (VirtualTable *)tab; ConstraintSet constraints; // Keep track of the index used for each valid constraint. // Expect this index to correspond with argv within xFilter. size_t expr_index = 0; // If any constraints are unusable increment the cost of the index. double cost = 1; // Expressions operating on the same virtual table are loosely identified by // the consecutive sets of terms each of the constraint sets are applied onto. // Subsequent attempts from failed (unusable) constraints replace the set, // while new sets of terms append. if (pIdxInfo->nConstraint > 0) { for (size_t i = 0; i < static_cast<size_t>(pIdxInfo->nConstraint); ++i) { // Record the term index (this index exists across all expressions). const auto &constraint_info = pIdxInfo->aConstraint[i]; #if defined(DEBUG) plan("Evaluating constraints for table: " + pVtab->content->name + " [index=" + std::to_string(i) + " column=" + std::to_string(constraint_info.iColumn) + " term=" + std::to_string((int)constraint_info.iTermOffset) + " usable=" + std::to_string((int)constraint_info.usable) + "]"); #endif if (!constraint_info.usable) { // A higher cost less priority, prefer more usable query constraints. cost += 10; continue; } // Lookup the column name given an index into the table column set. if (constraint_info.iColumn < 0 || static_cast<size_t>(constraint_info.iColumn) >= pVtab->content->columns.size()) { cost += 10; continue; } const auto &name = pVtab->content->columns[constraint_info.iColumn].first; // Save a pair of the name and the constraint operator. // Use this constraint during xFilter by performing a scan and column // name lookup through out all cursor constraint lists. constraints.push_back( std::make_pair(name, Constraint(constraint_info.op))); pIdxInfo->aConstraintUsage[i].argvIndex = ++expr_index; #if defined(DEBUG) plan("Adding constraint for table: " + pVtab->content->name + " [column=" + name + " arg_index=" + std::to_string(expr_index) + "]"); #endif } } pIdxInfo->idxNum = kConstraintIndexID++; // Add the constraint set to the table's tracked constraints. #if defined(DEBUG) plan("Recording constraint set for table: " + pVtab->content->name + " [cost=" + std::to_string(cost) + " size=" + std::to_string(constraints.size()) + " idx=" + std::to_string(pIdxInfo->idxNum) + "]"); #endif pVtab->content->constraints[pIdxInfo->idxNum] = std::move(constraints); pIdxInfo->estimatedCost = cost; return SQLITE_OK; }