package support; import java.util.*; /** * DieselAlgorithm — algorithmic models of Diesel (Rust) CWE-407 defects. * * Three defects modelled: * * diesel-0001: SqliteRow Duplicated RowIndex<&str> * column_names.iter().position() — O(N_cols) per named-column access. * Called once per deserialized field access on a duplicated row. * * diesel-0002: OwnedSqliteRow RowIndex<&str> * Same pattern on the owned (long-lived) variant. * * diesel-0003: MysqlRow RowIndex<&str> * metadata.fields().iter().enumerate().find() — O(N_cols) linear scan. */ public class DieselAlgorithm { public static class Result { public final int defectiveOps; public final int fixedOps; public Result(int defectiveOps, int fixedOps) { this.defectiveOps = defectiveOps; this.fixedOps = fixedOps; } } // ----------------------------------------------------------------------- // diesel-0001/0002: SQLite Duplicated row — named column lookup // // Pattern: for each row in result set, for each named-column access, // scan the column_names slice for a matching name. // // Cost: O(rows × cols_accessed × total_cols) // Fixed: build index map once per statement; O(rows × cols_accessed × log(total_cols)) // ----------------------------------------------------------------------- /** * Defective: linear scan for column name on every access. * * @param totalCols total columns in the result set (width of row) * @param colsAccessed number of named-column accesses per row * @param numRows number of rows in the result set * @return total position-scan steps (cost metric) */ public static long sqliteRowDefective(int totalCols, int colsAccessed, int numRows) { // Simulate column_names as a list (Rust: Rc<[Option]>) List columnNames = new ArrayList<>(); for (int c = 0; c < totalCols; c++) { columnNames.add("col_" + c); } long totalScanSteps = 0; for (int r = 0; r < numRows; r++) { for (int a = 0; a < colsAccessed; a++) { String target = "col_" + (a % totalCols); // Simulate: column_names.iter().position(|n| n == target) for (int i = 0; i < columnNames.size(); i++) { totalScanSteps++; if (columnNames.get(i).equals(target)) break; } } } return totalScanSteps; } /** * Fixed: build a Map once per statement (once, not per row), * then O(log N) lookup per access via TreeMap. * * @param totalCols total columns * @param colsAccessed named-column accesses per row * @param numRows rows in result set * @return total lookup steps (cost metric) */ public static long sqliteRowFixed(int totalCols, int colsAccessed, int numRows) { List columnNames = new ArrayList<>(); for (int c = 0; c < totalCols; c++) { columnNames.add("col_" + c); } // Build index map ONCE (per statement / per Duplicated construction) Map columnNameIndex = new TreeMap<>(); for (int i = 0; i < columnNames.size(); i++) { columnNameIndex.put(columnNames.get(i), i); } long totalLookupOps = 0; for (int r = 0; r < numRows; r++) { for (int a = 0; a < colsAccessed; a++) { String target = "col_" + (a % totalCols); // O(log N) TreeMap lookup totalLookupOps++; columnNameIndex.get(target); // O(log totalCols) } } return totalLookupOps; } // ----------------------------------------------------------------------- // diesel-0003: MySQL row — named column lookup // Same linear scan pattern, same fix. // ----------------------------------------------------------------------- /** * Defective: metadata.fields().iter().enumerate().find() — O(N_cols) per access. */ public static long mysqlRowDefective(int totalCols, int colsAccessed, int numRows) { return sqliteRowDefective(totalCols, colsAccessed, numRows); } /** * Fixed: build BTreeMap once per MysqlRow construction. */ public static long mysqlRowFixed(int totalCols, int colsAccessed, int numRows) { return sqliteRowFixed(totalCols, colsAccessed, numRows); } // ----------------------------------------------------------------------- // Complexity ratio helper // ----------------------------------------------------------------------- /** Returns the ratio defective/fixed scan steps for a given configuration. */ public static double complexityRatio(int totalCols, int colsAccessed, int numRows) { long def = sqliteRowDefective(totalCols, colsAccessed, numRows); long fix = sqliteRowFixed(totalCols, colsAccessed, numRows); return (double) def / fix; } }