package unit; import java.util.*; import java.util.stream.*; /** * Standalone unit test for doris-0001: * BindExpression.processNonStandardAggregate — List.contains() per projection → O(P×G). * * Simulates processNonStandardAggregate(): * for each projection, check if it's in groupingExprs (passed as List). * * Compile: javac -d . BindExprGroupingAlgorithm.java * Run: java unit.BindExprGroupingAlgorithm */ public class BindExprGroupingAlgorithm { // ── Expression stubs ───────────────────────────────────────────────────── static class Expression { final String id; Expression(String id) { this.id = id; } @Override public boolean equals(Object o) { return o instanceof Expression && id.equals(((Expression) o).id); } @Override public int hashCode() { return id.hashCode(); } @Override public String toString() { return id; } } static class SlotReference extends Expression { SlotReference(String id) { super(id); } } // ── Result ─────────────────────────────────────────────────────────────── static class Result { final List output; // projection labels: "alias:X" or "keep:X" final long ns; Result(List output, long ns) { this.output = output; this.ns = ns; } } // ── Defective: Collection as List → O(G) .contains per proj ─ static class DefectiveAlgorithm { Result processNonStandardAggregate( List originalProjections, Collection groupingExprs) { // List passed → O(G) .contains long t0 = System.nanoTime(); List out = new ArrayList<>(); for (Expression projection : originalProjections) { if (projection instanceof SlotReference && !groupingExprs.contains(projection)) { // CWE-407 site out.add("alias:" + projection.id); } else { out.add("keep:" + projection.id); } } return new Result(out, System.nanoTime() - t0); } } // ── Fixed: convert to Set once → O(1) .contains ────────────────────────── static class FixedAlgorithm { Result processNonStandardAggregate( List originalProjections, Collection groupingExprs) { long t0 = System.nanoTime(); // Ensure O(1) membership Set groupingSet = (groupingExprs instanceof Set) ? (Set) groupingExprs : new HashSet<>(groupingExprs); // O(G) once List out = new ArrayList<>(); for (Expression projection : originalProjections) { if (projection instanceof SlotReference && !groupingSet.contains(projection)) { // O(1) out.add("alias:" + projection.id); } else { out.add("keep:" + projection.id); } } return new Result(out, System.nanoTime() - t0); } } // ── Helpers ────────────────────────────────────────────────────────────── static List makeProjections(int P, int G) { // First G projections are SlotReferences that ARE in groupingExprs → "keep" // Next (P-G) are SlotReferences NOT in groupingExprs → "alias" List list = new ArrayList<>(P); for (int i = 0; i < P; i++) { list.add(new SlotReference("s" + i)); } return list; } static List makeGroupingList(int G) { List list = new ArrayList<>(G); for (int i = 0; i < G; i++) list.add(new SlotReference("s" + i)); return list; } // ── Assertions ─────────────────────────────────────────────────────────── static void assertEquals(Object expected, Object actual, String msg) { if (!expected.equals(actual)) throw new AssertionError(msg + ": expected=" + expected + " actual=" + actual); } static void assertTrue(boolean cond, String msg) { if (!cond) throw new AssertionError(msg); } public static void main(String[] args) { System.out.println("=== doris-0001: BindExprGroupingAlgorithm ==="); DefectiveAlgorithm defAlg = new DefectiveAlgorithm(); FixedAlgorithm fixAlg = new FixedAlgorithm(); // Correctness: small case { int P = 10, G = 4; List projections = makeProjections(P, G); List grouping = makeGroupingList(G); Result dr = defAlg.processNonStandardAggregate(projections, grouping); Result fr = fixAlg.processNonStandardAggregate(projections, grouping); assertEquals(dr.output, fr.output, "output labels"); // First G should be "keep:", rest "alias:" for (int i = 0; i < G; i++) assertTrue(dr.output.get(i).startsWith("keep:"), "keep at " + i); for (int i = G; i < P; i++) assertTrue(dr.output.get(i).startsWith("alias:"), "alias at " + i); System.out.println("PASS correctness (P=10, G=4)"); } // Correctness: Set passed directly (should not double-wrap) { int P = 8, G = 3; List projections = makeProjections(P, G); Set groupingSet = new HashSet<>(makeGroupingList(G)); Result dr = defAlg.processNonStandardAggregate(projections, new ArrayList<>(groupingSet)); Result fr = fixAlg.processNonStandardAggregate(projections, groupingSet); assertEquals(dr.output, fr.output, "Set input output labels"); System.out.println("PASS correctness Set input (P=8, G=3)"); } // Benchmark at P=400, G=200 { int P = 400, G = 200; List projections = makeProjections(P, G); List grouping = makeGroupingList(G); // warm up for (int i = 0; i < 5; i++) { defAlg.processNonStandardAggregate(projections, new ArrayList<>(grouping)); fixAlg.processNonStandardAggregate(projections, new ArrayList<>(grouping)); } long defNs = 0, fixNs = 0; int reps = 50; for (int i = 0; i < reps; i++) { defNs += defAlg.processNonStandardAggregate(projections, new ArrayList<>(grouping)).ns; fixNs += fixAlg.processNonStandardAggregate(projections, new ArrayList<>(grouping)).ns; } defNs /= reps; fixNs /= reps; double ratio = (double) defNs / Math.max(1, fixNs); System.out.printf("BENCH P=%d G=%d reps=%d%n", P, G, reps); System.out.printf(" defective avg: %,d ns%n", defNs); System.out.printf(" fixed avg: %,d ns%n", fixNs); System.out.printf(" speedup: %.1fx%n", ratio); assertTrue(ratio >= 2.0, "Expected fixed >= 2x faster, got " + ratio + "x"); System.out.println("PASS speedup >= 2x"); } System.out.println("=== ALL PASS ==="); } }