package unit; import java.util.*; /** * SQLAlchemyTest — sqlalchemy-0001..0002 * * Proves CWE-407 in SQLAlchemy: * sqlalchemy-0001: SQLCompiler._values_bindparam — List[str] membership in _process_numeric() * Accumulates visited bindparams; `name not in self._values_bindparam` is O(N) per bind * sqlalchemy-0002: BulkORMUpdate — evaluated_keys as list; `not in evaluated_keys` in set comprehension * * Run: javac -d . SQLAlchemyTest.java && java -ea unit.SQLAlchemyTest */ public class SQLAlchemyTest { // ── sqlalchemy-0001: _values_bindparam list membership ─────────────────── /** * SLOW: _values_bindparam as List — `name not in _values_bindparam` is O(N) per call. * Called once per bind parameter in _process_numeric(). O(B²) total for B bind params. */ static long valuesBindparamSlow(int numBinds) { List valuesBindparam = new ArrayList<>(); long ops = 0; for (int i = 0; i < numBinds; i++) { String name = "param_" + i; // `name not in self._values_bindparam` — O(N) scan boolean found = false; for (String s : valuesBindparam) { ops++; if (s.equals(name)) { found = true; break; } } if (!found) valuesBindparam.add(name); } return ops; } /** FAST: _values_bindparam as Set — O(1) per membership test. O(B) total. */ static long valuesBindparamFast(int numBinds) { Set valuesBindparamSet = new HashSet<>(); long ops = 0; for (int i = 0; i < numBinds; i++) { String name = "param_" + i; ops++; // O(1) set.add valuesBindparamSet.add(name); } return ops; } // ── sqlalchemy-0002: evaluated_keys list in ORM bulk update ────────────── /** * SLOW: evaluated_keys as list — `key not in evaluated_keys` is O(K) per key. * Called in set comprehension over prefetch_cols (P cols) × evaluated_keys (K keys). * O(P × K) total. */ static long evaluatedKeysSlow(int numPrefetchCols, int numEvaluatedKeys) { List evaluatedKeys = new ArrayList<>(); for (int i = 0; i < numEvaluatedKeys; i++) evaluatedKeys.add("key_" + i); long ops = 0; // Simulate: {c for c in prefetch_cols if c.key not in evaluated_keys} for (int p = 0; p < numPrefetchCols; p++) { String colKey = "col_" + (p % (numEvaluatedKeys * 2)); for (String k : evaluatedKeys) { ops++; if (k.equals(colKey)) break; } } return ops; } /** FAST: evaluated_keys as Set — O(1) per membership test. O(P) total. */ static long evaluatedKeysFast(int numPrefetchCols, int numEvaluatedKeys) { Set evaluatedKeysSet = new HashSet<>(); for (int i = 0; i < numEvaluatedKeys; i++) evaluatedKeysSet.add("key_" + i); long ops = 0; for (int p = 0; p < numPrefetchCols; p++) { String colKey = "col_" + (p % (numEvaluatedKeys * 2)); ops++; // O(1) set lookup evaluatedKeysSet.contains(colKey); } return ops; } static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) { slow.run(); fast.run(); long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime()-t0)/1_000_000; long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime()-t1)/1_000_000; double r = fOps > 0 ? (double)sOps/fOps : 0; System.out.printf(" %-52s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n", label, sMs, sOps, fMs, fOps, r); } public static void main(String[] args) { System.out.println("=== UNIT sqlalchemy-0001..0002: SQLAlchemy CWE-407 ==="); System.out.println(); final int BINDS = 1000; // sqlalchemy-0001 final int PREFETCH = 500, KEYS = 500; // sqlalchemy-0002 long s0 = valuesBindparamSlow(BINDS), f0 = valuesBindparamFast(BINDS); bench("sqlalchemy-0001 _values_bindparam List membership", () -> valuesBindparamSlow(BINDS), () -> valuesBindparamFast(BINDS), s0, f0); long s1 = evaluatedKeysSlow(PREFETCH, KEYS), f1 = evaluatedKeysFast(PREFETCH, KEYS); bench("sqlalchemy-0002 evaluated_keys List in set comprehension", () -> evaluatedKeysSlow(PREFETCH, KEYS), () -> evaluatedKeysFast(PREFETCH, KEYS), s1, f1); System.out.println(); int pass = 0; assert s0 > f0 * 5 : "sqlalchemy-0001 expected >5x"; pass++; assert s1 > f1 * 5 : "sqlalchemy-0002 expected >5x"; pass++; System.out.printf("%d/2 PASS — sqlalchemy-0001..0002: CWE-407 in SQLAlchemy SQL compiler/ORM%n", pass); System.out.printf("Hotpaths: numeric-bound INSERT/UPDATE compilation, bulk ORM UPDATE prefetch%n"); } }