diff --git a/.github/workflows/codegen-test.yml b/.github/workflows/codegen-test.yml index 85022d6..9c30354 100644 --- a/.github/workflows/codegen-test.yml +++ b/.github/workflows/codegen-test.yml @@ -39,8 +39,4 @@ jobs: with: name: generated-code path: | - src/main/java/org/qed/Generated/*.java - !src/main/java/org/qed/Generated/CalciteTester.java - !src/main/java/org/qed/Generated/CalciteGenerator.java - !src/main/java/org/qed/Generated/CalciteUtilities.java - !src/main/java/org/qed/Generated/EmptyConfig.java \ No newline at end of file + src/main/java/org/qed/Backends/Calcite/Generated/*.java \ No newline at end of file diff --git a/pom.xml b/pom.xml index fd29e81..3802e5f 100644 --- a/pom.xml +++ b/pom.xml @@ -108,9 +108,9 @@ 0.0.7-v5 - org.reflections - reflections - 0.10.2 + com.mysql + mysql-connector-j + 8.0.33 \ No newline at end of file diff --git a/scripts/generate-rule-json.sh b/scripts/generate-rule-json.sh index a34f5da..172b0e5 100644 --- a/scripts/generate-rule-json.sh +++ b/scripts/generate-rule-json.sh @@ -33,7 +33,7 @@ CLASSPATH="target/classes:${MAVEN_CP}" javac -cp "$CLASSPATH" JsonGenerator.java # Generate JSON for each rule -find src/main/java/org/qed/Generated/RRuleInstances -name '*.java' | while read file; do +find src/main/java/org/qed/RRuleInstances -name '*.java' | while read file; do className=$(echo "$file" | sed 's|src/main/java/||; s|/|.|g; s|\.java$||') echo "Generating JSON for: $className" java -cp ".:$CLASSPATH" JsonGenerator "$className" diff --git a/scripts/test-codegen.sh b/scripts/test-codegen.sh index 6ab614e..064b171 100644 --- a/scripts/test-codegen.sh +++ b/scripts/test-codegen.sh @@ -8,7 +8,7 @@ echo "" >> $GITHUB_STEP_SUMMARY # Step 1: Generate code for each rule in RRuleInstances # Create temporary Java file for code generation cat > RuleGenerator.java << 'EOF' -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.*; import java.nio.file.*; @@ -34,17 +34,15 @@ CLASSPATH="target/classes:${MAVEN_CP}" javac -cp "$CLASSPATH" RuleGenerator.java # Generate code for each rule -find src/main/java/org/qed/Generated/RRuleInstances -name '*.java' -not -path '*/RRuleInstances-unprovable/*' | while read file; do +find src/main/java/org/qed/RRuleInstances -name '*.java' -not -path '*/RRuleInstances-unprovable/*' | while read file; do className=$(echo "$file" | sed 's|src/main/java/||; s|/|.|g; s|\.java$||') java -cp ".:$CLASSPATH" RuleGenerator "$className" done # Step 2: Check for missing tests -missing_tests="" -missing_count=0 -for rule_file in src/main/java/org/qed/Generated/RRuleInstances/*.java; do +for rule_file in src/main/java/org/qed/RRuleInstances/*.java; do rule_name=$(basename "$rule_file" .java) - if [ ! -f "src/main/java/org/qed/Generated/Tests/${rule_name}Test.java" ]; then + if [ ! -f "src/main/java/org/qed/Backends/Calcite/Tests/${rule_name}Test.java" ]; then missing_tests="${missing_tests}- ${rule_name}\n" missing_count=$((missing_count + 1)) fi @@ -65,7 +63,7 @@ passed_tests=0 total_tests=0 passed_tests=0 -for test_file in src/main/java/org/qed/Generated/Tests/*Test.java; do +for test_file in src/main/java/org/qed/Backends/Calcite/Tests/*Test.java; do class_name=${test_file#src/main/java/} class_name=${class_name%.java} class_name=${class_name//\//.} diff --git a/src/main/java/org/qed/Generated/CalciteGenerator.java b/src/main/java/org/qed/Backends/Calcite/CalciteGenerator.java similarity index 86% rename from src/main/java/org/qed/Generated/CalciteGenerator.java rename to src/main/java/org/qed/Backends/Calcite/CalciteGenerator.java index ee158fd..572c740 100644 --- a/src/main/java/org/qed/Generated/CalciteGenerator.java +++ b/src/main/java/org/qed/Backends/Calcite/CalciteGenerator.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite; import kala.collection.Seq; import kala.collection.immutable.ImmutableMap; @@ -7,7 +7,7 @@ import org.qed.CodeGenerator; import org.qed.RelRN; import org.qed.RexRN; -import org.qed.Generated.CalciteGenerator.Env; +import org.qed.Backends.Calcite.CalciteGenerator.Env; import java.util.concurrent.atomic.AtomicInteger; @@ -99,7 +99,6 @@ public Env onMatchProj(Env env, RexRN.Proj proj) { @Override public Env onMatchJoin(Env env, RelRN.Join join) { var current_join = "((LogicalJoin) " + env.current() + ")"; - // STR."\{join_env.current()}.getJoinType()" var left_source_env = env.next(); var left_match_env = onMatch(left_source_env, join.left()); var right_source_env = left_match_env.next(); @@ -112,14 +111,9 @@ public Env onMatchJoin(Env env, RelRN.Join join) { @Override public Env onMatchAnd(Env env, RexRN.And and) { - // Process each source in the And condition var current_env = env; - // Use a unique symbol name for the AND condition String andSymbol = "and_" + env.varId.getAndIncrement(); - // Store the current expression as this AND node's symbol current_env = current_env.symbol(andSymbol, current_env.current()); - - // Process each child source in the AND condition for (var source : and.sources()) { current_env = onMatch(current_env, source); } @@ -129,22 +123,15 @@ public Env onMatchAnd(Env env, RexRN.And and) { @Override public Env onMatchUnion(Env env, RelRN.Union union) { - // Get the all flag from the union boolean all = union.all(); - - // Process each source in the union var current_env = env; var skeletons = Seq.empty(); - - // Process all sources in the sequence for (var source : union.sources()) { var next_env = current_env.next(); var source_env = onMatch(next_env, source); skeletons = skeletons.appended(source_env.skeleton()); current_env = source_env; } - - // Build the input skeletons string for the operand StringBuilder inputsBuilder = new StringBuilder(); for (int i = 0; i < skeletons.size(); i++) { if (i > 0) { @@ -152,30 +139,21 @@ public Env onMatchUnion(Env env, RelRN.Union union) { } inputsBuilder.append(skeletons.get(i).toString()); } - - // Create the union operand with the appropriate class based on the all flag String operatorClass = all ? "LogicalUnionAll" : "LogicalUnion"; return current_env.grow("operand(" + operatorClass + ".class).inputs(" + inputsBuilder.toString() + ")"); } @Override public Env onMatchIntersect(Env env, RelRN.Intersect intersect) { - // Get the all flag from the intersect boolean all = intersect.all(); - - // Process each source in the intersect var current_env = env; var skeletons = Seq.empty(); - - // Process all sources in the sequence for (var source : intersect.sources()) { var next_env = current_env.next(); var source_env = onMatch(next_env, source); skeletons = skeletons.appended(source_env.skeleton()); current_env = source_env; } - - // Build the input skeletons string for the operand StringBuilder inputsBuilder = new StringBuilder(); for (int i = 0; i < skeletons.size(); i++) { if (i > 0) { @@ -183,30 +161,21 @@ public Env onMatchIntersect(Env env, RelRN.Intersect intersect) { } inputsBuilder.append(skeletons.get(i).toString()); } - - // Create the intersect operand with the appropriate class based on the all flag String operatorClass = all ? "LogicalIntersectAll" : "LogicalIntersect"; return current_env.grow("operand(" + operatorClass + ".class).inputs(" + inputsBuilder.toString() + ")"); } @Override public Env onMatchMinus(Env env, RelRN.Minus minus) { - // Get the all flag from the minus boolean all = minus.all(); - - // Process each source in the minus var current_env = env; var skeletons = Seq.empty(); - - // Process all sources in the sequence for (var source : minus.sources()) { var next_env = current_env.next(); var source_env = onMatch(next_env, source); skeletons = skeletons.appended(source_env.skeleton()); current_env = source_env; } - - // Build the input skeletons string for the operand StringBuilder inputsBuilder = new StringBuilder(); for (int i = 0; i < skeletons.size(); i++) { if (i > 0) { @@ -214,35 +183,24 @@ public Env onMatchMinus(Env env, RelRN.Minus minus) { } inputsBuilder.append(skeletons.get(i).toString()); } - - // Create the minus operand return current_env.grow("operand(LogicalMinus.class).inputs(" + inputsBuilder.toString() + ")"); } @Override public Env onMatchField(Env env, RexRN.Field field) { - // Generate a unique symbolic name for this field String fieldSymbol = "field_" + env.varId.getAndIncrement(); - - // Store the field expression in the environment's symbol table return env.symbol(fieldSymbol, env.current()); } @Override public Env onMatchTrue(Env env, RexRN literal) { - // Create a unique symbol name for this true literal String trueSymbol = "true_" + env.varId.getAndIncrement(); - - // Store the current expression as this true literal's symbol return env.symbol(trueSymbol, env.current()); } @Override public Env onMatchFalse(Env env, RexRN literal) { - // Create a unique symbol name for this false literal String falseSymbol = "false_" + env.varId.getAndIncrement(); - - // Store the current expression as this false literal's symbol return env.symbol(falseSymbol, env.current()); } @@ -323,37 +281,23 @@ else if (env.rulename.equals("FilterAggregateTranspose")) { @Override public Env transformJoinField(Env env, RexRN.JoinField joinField) { - // For JoinCommute: we need to calculate absolute field positions in the swapped join - // Get the original join condition to extract the actual field indices var origJoinDecl = env.declare("(LogicalJoin) call.rel(0)"); var envWithOrigJoin = origJoinDecl.getValue(); var conditionDecl = envWithOrigJoin.declare("(org.apache.calcite.rex.RexCall) " + origJoinDecl.getKey() + ".getCondition()"); var envWithCondition = conditionDecl.getValue(); if (joinField.ordinal() == 0) { - // Ordinal 0 = Left table in original join - // Extract the left operand field index from original condition var leftFieldDecl = envWithCondition.declare("((org.apache.calcite.rex.RexInputRef) " + conditionDecl.getKey() + ".getOperands().get(0)).getIndex()"); var envWithLeftField = leftFieldDecl.getValue(); - - // In swapped join: Left table is now at input 1 - // Use field(2, 1, leftFieldIndex) syntax return envWithLeftField.focus(env.current() + ".field(2, 1, " + leftFieldDecl.getKey() + ")"); } else if (joinField.ordinal() == 1) { - // Ordinal 1 = Right table in original join - // Extract the right operand field index from original condition var rightFieldDecl = envWithCondition.declare("((org.apache.calcite.rex.RexInputRef) " + conditionDecl.getKey() + ".getOperands().get(1)).getIndex()"); var envWithRightField = rightFieldDecl.getValue(); - - // Right table field index needs to be adjusted since it was originally after left table var leftColCountDecl = envWithRightField.declare("call.rel(1).getRowType().getFieldCount()"); var envWithLeftCount = leftColCountDecl.getValue(); var adjustedRightFieldDecl = envWithLeftCount.declare(rightFieldDecl.getKey() + " - " + leftColCountDecl.getKey()); var envWithAdjustedRightField = adjustedRightFieldDecl.getValue(); - - // In swapped join: Right table is now at input 0 - // Use field(2, 0, adjustedRightFieldIndex) syntax return envWithAdjustedRightField.focus(env.current() + ".field(2, 0, " + adjustedRightFieldDecl.getKey() + ")"); } else { throw new UnsupportedOperationException("Unsupported join field ordinal: " + joinField.ordinal()); @@ -429,59 +373,35 @@ public Env transformAnd(Env env, RexRN.And and) { @Override public Env transformUnion(Env env, RelRN.Union union) { - // Get the all flag from the union boolean all = union.all(); - - // The number of sources int sourceCount = union.sources().size(); - - // Transform each source var current_env = env; for (var source : union.sources()) { current_env = transform(current_env, source); } - - // Use the union method with the all flag and source count - // This matches the Calcite RelBuilder.union(boolean all, int n) signature return current_env.focus(current_env.current() + ".union(" + all + ", " + sourceCount + ")"); } @Override public Env transformIntersect(Env env, RelRN.Intersect intersect) { - // Get the all flag from the intersect boolean all = intersect.all(); - - // The number of sources int sourceCount = intersect.sources().size(); - - // Transform each source var current_env = env; for (var source : intersect.sources()) { current_env = transform(current_env, source); } - - // Use the intersect method with the all flag and source count - // This matches the expected Calcite RelBuilder.intersect(boolean all, int n) signature String methodName = all ? "intersectAll" : "intersect"; return current_env.focus(current_env.current() + "." + methodName + "(" + all + ", " + sourceCount + ")"); } @Override public Env transformMinus(Env env, RelRN.Minus minus) { - // Get the all flag from the minus boolean all = minus.all(); - - // The number of sources int sourceCount = minus.sources().size(); - - // Transform each source var current_env = env; for (var source : minus.sources()) { current_env = transform(current_env, source); } - - // Use the minus method with the all flag and source count - // This matches the expected Calcite RelBuilder.minus(boolean all, int n) signature return current_env.focus(current_env.current() + ".minus(" + all + ", " + sourceCount + ")"); } @@ -530,11 +450,8 @@ public Env transformEmpty(Env env, RelRN.Empty empty) { @Override public Env transformCustom(Env env, RelRN custom) { return switch (custom) { - case org.qed.Generated.RRuleInstances.JoinCommute.ProjectionRelRN projection -> { - // Transform the source first - this builds the join + case org.qed.RRuleInstances.JoinCommute.ProjectionRelRN projection -> { var sourceEnv = transform(env, projection.source()); - - // Get original table column counts var leftTableDecl = sourceEnv.declare("call.rel(1)"); var envWithLeftTable = leftTableDecl.getValue(); var rightTableDecl = envWithLeftTable.declare("call.rel(2)"); @@ -544,26 +461,18 @@ public Env transformCustom(Env env, RelRN custom) { var envWithLeftCount = leftColCountDecl.getValue(); var rightColCountDecl = envWithLeftCount.declare(rightTableDecl.getKey() + ".getRowType().getFieldCount()"); var envWithRightCount = rightColCountDecl.getValue(); - - // Create the projection indices as a List var projectionIndicesDecl = envWithRightCount.declare( "java.util.stream.IntStream.concat(" + - // Left columns: rightColCount + 0, rightColCount + 1, ..., rightColCount + leftColCount - 1 "java.util.stream.IntStream.range(" + rightColCountDecl.getKey() + ", " + rightColCountDecl.getKey() + " + " + leftColCountDecl.getKey() + "), " + - // Right columns: 0, 1, ..., rightColCount - 1 "java.util.stream.IntStream.range(0, " + rightColCountDecl.getKey() + ")" + ").boxed().collect(java.util.stream.Collectors.toList())" ); var envWithProjectionIndices = projectionIndicesDecl.getValue(); - - // Convert List to field references using RelBuilder.fields() var fieldRefsDecl = envWithProjectionIndices.declare( sourceEnv.current() + ".fields(" + projectionIndicesDecl.getKey() + ")" ); var envWithFieldRefs = fieldRefsDecl.getValue(); - - // Apply projection using the field references list yield envWithFieldRefs.focus(sourceEnv.current() + ".project(" + fieldRefsDecl.getKey() + ")"); } default -> unimplementedTransform(env, custom); diff --git a/src/main/java/org/qed/Generated/CalciteTester.java b/src/main/java/org/qed/Backends/Calcite/CalciteTester.java similarity index 61% rename from src/main/java/org/qed/Generated/CalciteTester.java rename to src/main/java/org/qed/Backends/Calcite/CalciteTester.java index a6ff83b..98454c4 100644 --- a/src/main/java/org/qed/Generated/CalciteTester.java +++ b/src/main/java/org/qed/Backends/Calcite/CalciteTester.java @@ -1,22 +1,21 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite; -import com.fasterxml.jackson.databind.ObjectMapper; -import kala.collection.Seq; import kala.tuple.Tuple; +import kala.collection.Seq; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.qed.*; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.apache.calcite.jdbc.CalcitePrepare.SparkHandler.RuleSetBuilder; -import org.apache.calcite.plan.RelOptRule; -import org.apache.calcite.plan.hep.HepPlanner; -import org.apache.calcite.plan.hep.HepProgramBuilder; +import org.apache.calcite.rel.rules.*; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.LogicalFilter; import org.apache.calcite.rel.logical.LogicalValues; -import org.apache.calcite.rex.RexNode; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.*; -import org.reflections.Reflections; -import org.apache.calcite.rel.rules.*; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.hep.HepPlanner; +import org.apache.calcite.plan.hep.HepProgramBuilder; import java.io.File; import java.io.IOException; @@ -28,12 +27,11 @@ import java.util.stream.Collectors; public class CalciteTester { - // Assuming that current working directory is the root of the project - public static String genPath = "src/main/java/org/qed/Generated"; + public static String genPath = "src/main/java/org/qed/Backends/Calcite/Generated"; public static String rulePath = "rules"; public static HepPlanner loadRules(java.util.List rules) { - System.out.printf("Verifying Rules: %s\n", + System.out.printf("Loading Rules: %s\n", rules.stream() .map(rule -> rule.getClass().getSimpleName()) .collect(java.util.stream.Collectors.joining(", "))); @@ -50,13 +48,13 @@ public static HepPlanner loadRules(RelOptRule... rules) { } public static HepPlanner loadRule(RelOptRule rule) { - System.out.printf("Verifying Rule: %s\n", rule.getClass()); + System.out.printf("Loading Rule: %s\n", rule.getClass().getSimpleName()); var builder = new HepProgramBuilder().addRuleInstance(rule); return new HepPlanner(builder.build()); } public static HepPlanner loadRule(RelOptRule rule, int matchLimit) { - System.out.printf("Verifying Rule: %s (match limit: %d)\n", rule.getClass(), matchLimit); + System.out.printf("Loading Rule: %s (match limit: %d)\n", rule.getClass().getSimpleName(), matchLimit); var builder = new HepProgramBuilder() .addMatchLimit(matchLimit) .addRuleInstance(rule); @@ -64,24 +62,32 @@ public static HepPlanner loadRule(RelOptRule rule, int matchLimit) { } public static Seq ruleList() { - Reflections reflections = new Reflections("org.qed.Generated.RRuleInstances"); - - Set> ruleClasses = reflections.getSubTypesOf(RRule.class); - var concreteRuleClasses = ruleClasses.stream() - .filter(clazz -> !clazz.isInterface() && - !Modifier.isAbstract(clazz.getModifiers()) && - !clazz.getName().contains("$") - && !clazz.getSimpleName().equals("UnionPullUpConstants") - && !clazz.getSimpleName().equals("AggregateProjectConstantToDummyJoin") - && !clazz.getSimpleName().equals("ProjectAggregateMerge") - && !clazz.getSimpleName().equals("UnionToDistinct") - ) - .collect(Collectors.toSet()); + java.io.File ruleDir = new java.io.File("src/main/java/org/qed/RRuleInstances"); + java.io.File[] files = ruleDir.listFiles((dir, name) -> name.endsWith(".java")); + + java.util.List rules = new java.util.ArrayList<>(); - var individuals = Seq.from(concreteRuleClasses) - .mapUnchecked(Class::getConstructor) - .mapUnchecked(Constructor::newInstance) - .map(r -> (RRule) r); + if (files != null) { + for (java.io.File file : files) { + String className = file.getName().replace(".java", ""); + if (className.equals("UnionPullUpConstants") || + className.equals("AggregateProjectConstantToDummyJoin") || + className.equals("ProjectAggregateMerge") || + className.equals("UnionToDistinct")) { + continue; + } + + try { + Class clazz = Class.forName("org.qed.RRuleInstances." + className); + RRule rule = (RRule) clazz.getConstructor().newInstance(); + rules.add(rule); + } catch (Exception e) { + throw new RuntimeException("Failed to load rule: " + className, e); + } + } + } + + return Seq.from(rules); // var families = Seq.from(reflections.getSubTypesOf(RRule.RRuleFamily.class)) // .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) @@ -93,7 +99,6 @@ public static Seq ruleList() { // .map(r -> (RRule.RRuleFamily) r); // return individuals.appendedAll(families.flatMap(RRule.RRuleFamily::family)); - return individuals; } public static void verify() { @@ -106,35 +111,27 @@ public static void generate() { } public static void runAllTests() { - try { - // org.qed.Generated.Tests.FilterIntoJoinTest.runTest(); - // org.qed.Generated.Tests.FilterMergeTest.runTest(); - // org.qed.Generated.Tests.FilterProjectTransposeTest.runTest(); - // org.qed.Generated.Tests.UnionMergeTest.runTest(); - // org.qed.Generated.Tests.IntersectMergeTest.runTest(); - // org.qed.Generated.Tests.FilterSetOpTransposeTest.runTest(); - // org.qed.Generated.Tests.JoinExtractFilterTest.runTest(); - // org.qed.Generated.Tests.SemiJoinFilterTransposeTest.runTest(); - // org.qed.Generated.Tests.MinusMergeTest.runTest(); - // org.qed.Generated.Tests.ProjectFilterTransposeTest.runTest(); - // org.qed.Generated.Tests.JoinPushTransitivePredicatesTest.runTest(); - // org.qed.Generated.Tests.JoinCommuteTest.runTest(); - // org.qed.Generated.Tests.JoinConditionPushTest.runTest(); - // org.qed.Generated.Tests.AggregateProjectMergeTest.runTest(); - // org.qed.Generated.Tests.AggregateFilterTransposeTest.runTest(); - // org.qed.Generated.Tests.FilterAggregateTransposeTest.runTest(); - org.qed.Generated.Tests.AggregateExtractProjectTest.runTest(); - } catch (Exception e) { - System.out.println("Test failed: " + e.getMessage()); - e.printStackTrace(); + String packagePath = "src/main/java/org/qed/Backends/Calcite/Tests"; + java.io.File testDir = new java.io.File(packagePath); + java.io.File[] testFiles = testDir.listFiles((dir, name) -> name.endsWith("Test.java")); + if (testFiles != null) { + for (java.io.File testFile : testFiles) { + String className = "org.qed.Backends.Calcite.Tests." + testFile.getName().replace(".java", ""); + try { + Class testClass = Class.forName(className); + testClass.getMethod("runTest").invoke(null); + } catch (Exception e) { + throw new RuntimeException("Failed to run test: " + className, e); + } + } } } public static void main(String[] args) throws IOException { - var rule = new org.qed.Generated.RRuleInstances.AggregateExtractProject(); - System.out.println(rule.explain()); - Files.createDirectories(Path.of(rulePath)); - new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(Path.of(rulePath, rule.name() + "-" + rule.info() + ".json").toFile(), rule.toJson()); + // var rule = new org.qed.RRuleInstances.AggregateExtractProject(); + // System.out.println(rule.explain()); + // Files.createDirectories(Path.of(rulePath)); + // new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(Path.of(rulePath, rule.name() + "-" + rule.info() + ".json").toFile(), rule.toJson()); // var rules = new RRuleInstance.JoinAssociate(); // Files.createDirectories(Path.of(rulePath)); // for (var rule : rules.family()) { @@ -185,9 +182,6 @@ public void verify(HepPlanner runner, RelNode source, RelNode target) { else { System.out.println("succeeded"); - // System.out.println("> Given source RelNode:\n" + source.explain()); - // System.out.println("> Actual rewritten RelNode:\n" + answerExplain); - // System.out.println("> Expected rewritten RelNode:\n" + targetExplain); } return; } @@ -196,4 +190,4 @@ public void verify(HepPlanner runner, RelNode source, RelNode target) { System.out.println("> Actual rewritten RelNode:\n" + answerExplain); System.out.println("> Expected rewritten RelNode:\n" + targetExplain); } -} +} \ No newline at end of file diff --git a/src/main/java/org/qed/Backends/Calcite/CalciteUtilities.java b/src/main/java/org/qed/Backends/Calcite/CalciteUtilities.java new file mode 100644 index 0000000..deeedec --- /dev/null +++ b/src/main/java/org/qed/Backends/Calcite/CalciteUtilities.java @@ -0,0 +1,332 @@ +package org.qed.Backends.Calcite; + +import java.util.Set; +import java.util.Map; +import java.util.List; +import java.util.HashMap; +import java.util.HashSet; +import java.util.ArrayList; +import java.util.Collections; + +import org.qed.RuleBuilder; +import org.apache.calcite.util.ImmutableBitSet; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelOptUtil; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.core.Project; +import org.apache.calcite.rel.core.AggregateCall; +import org.apache.calcite.rel.logical.LogicalFilter; +import org.apache.calcite.rel.logical.LogicalProject; +import org.apache.calcite.rel.logical.LogicalAggregate; +import org.apache.calcite.rex.RexNode; +import org.apache.calcite.rex.RexUtil; +import org.apache.calcite.rex.RexCall; +import org.apache.calcite.rex.RexShuttle; +import org.apache.calcite.rex.RexInputRef; + +public class CalciteUtilities { + public List compose(RelNode base, List inner, List outer) { + var builder = RuleBuilder.create(); + return RelOptUtil.pushPastProject(outer, (Project) builder.push(base).project(inner).build()); + } + + public static org.apache.calcite.rex.RexNode mapFilterToProjectedColumns(RelOptRuleCall call) { + var filter = (LogicalFilter) call.rel(1); + var project = (LogicalProject) call.rel(0); + var rexBuilder = project.getCluster().getRexBuilder(); + var tableToProjectMapping = new HashMap(); + for (int projectedPos = 0; projectedPos < project.getProjects().size(); projectedPos++) { + var projectExpr = project.getProjects().get(projectedPos); + if (projectExpr instanceof RexInputRef inputRef) { + tableToProjectMapping.put(inputRef.getIndex(), projectedPos); + } + } + return filter.getCondition().accept(new RexShuttle() { + @Override + public org.apache.calcite.rex.RexNode visitInputRef(RexInputRef inputRef) { + Integer projectedPos = tableToProjectMapping.get(inputRef.getIndex()); + if (projectedPos != null) { + return rexBuilder.makeInputRef(inputRef.getType(), projectedPos); + } + return inputRef; + } + }); + } + + public static org.apache.calcite.rex.RexNode mapFilterToAggregatedColumns(RelOptRuleCall call) { + var filter = (LogicalFilter) call.rel(1); + var aggregate = (LogicalAggregate) call.rel(0); + var rexBuilder = aggregate.getCluster().getRexBuilder(); + var inputToAggregateMapping = new HashMap(); + int outputPos = 0; + for (int groupCol : aggregate.getGroupSet()) { + inputToAggregateMapping.put(groupCol, outputPos++); + } + return filter.getCondition().accept(new RexShuttle() { + @Override + public org.apache.calcite.rex.RexNode visitInputRef(RexInputRef inputRef) { + Integer aggregatedPos = inputToAggregateMapping.get(inputRef.getIndex()); + if (aggregatedPos != null) { + return rexBuilder.makeInputRef(inputRef.getType(), aggregatedPos); + } + throw new IllegalStateException( + "Filter references non-group column at index " + inputRef.getIndex() + + " which cannot be pushed past aggregate"); + } + }); + } + + public static org.apache.calcite.rex.RexNode pushFilterPastAggregate(RelOptRuleCall call) { + var filter = (LogicalFilter) call.rel(0); + var aggregate = (LogicalAggregate) call.rel(1); + var rexBuilder = aggregate.getCluster().getRexBuilder(); + var aggregateToInputMapping = new HashMap(); + int outputPos = 0; + for (int inputCol : aggregate.getGroupSet()) { + aggregateToInputMapping.put(outputPos++, inputCol); + } + return filter.getCondition().accept(new RexShuttle() { + @Override + public org.apache.calcite.rex.RexNode visitInputRef(RexInputRef inputRef) { + Integer originalPos = aggregateToInputMapping.get(inputRef.getIndex()); + if (originalPos != null) { + return rexBuilder.makeInputRef(inputRef.getType(), originalPos); + } + throw new IllegalStateException( + "Filter references non-group column at index " + inputRef.getIndex() + + " which cannot be pushed past aggregate"); + } + }); + } + + public static boolean canMergeAggregateProject(RelOptRuleCall call) { + var aggregate = (LogicalAggregate) call.rel(0); + var project = (LogicalProject) call.rel(1); + var interestingFields = org.apache.calcite.plan.RelOptUtil.getAllFields(aggregate); + for (int fieldIndex : interestingFields) { + var projectExpr = project.getProjects().get(fieldIndex); + if (!(projectExpr instanceof RexInputRef)) { + return false; + } + } + return true; + } + + public static org.apache.calcite.tools.RelBuilder createMergedAggregateProject(RelOptRuleCall call) { + var aggregate = (LogicalAggregate) call.rel(0); + var project = (LogicalProject) call.rel(1); + var builder = call.builder(); + var interestingFields = org.apache.calcite.plan.RelOptUtil.getAllFields(aggregate); + var fieldMapping = new HashMap(); + for (int fieldIndex : interestingFields) { + var projectExpr = project.getProjects().get(fieldIndex); + if (projectExpr instanceof RexInputRef inputRef) { + fieldMapping.put(fieldIndex, inputRef.getIndex()); + } + } + builder.push(project.getInput()); + var newGroupSet = aggregate.getGroupSet().permute(fieldMapping); + var groupKey = builder.groupKey(newGroupSet); + var mappedAggCalls = new java.util.ArrayList(); + var sourceCount = aggregate.getInput().getRowType().getFieldCount(); + var targetCount = project.getInput().getRowType().getFieldCount(); + var targetMapping = org.apache.calcite.util.mapping.Mappings.target( + fieldMapping, + sourceCount, + targetCount + ); + + for (var aggCall : aggregate.getAggCallList()) { + mappedAggCalls.add(aggCall.transform(targetMapping)); + } + builder.aggregate(groupKey, mappedAggCalls); + + var originalGroupList = aggregate.getGroupSet().asList(); + var newGroupList = newGroupSet.asList(); + var reorderingIndices = new java.util.ArrayList(); + for (int originalFieldIndex : originalGroupList) { + int mappedFieldIndex = fieldMapping.get(originalFieldIndex); + int positionInNewAggregate = newGroupList.indexOf(mappedFieldIndex); + reorderingIndices.add(positionInNewAggregate); + } + for (int i = aggregate.getGroupCount(); i < aggregate.getGroupCount() + aggregate.getAggCallList().size(); i++) { + reorderingIndices.add(i); + } + builder.project(builder.fields(reorderingIndices)); + + return builder; + } + + public static org.apache.calcite.tools.RelBuilder mergeProjections(RelOptRuleCall call) { + var outerProject = (LogicalProject) call.rel(0); + var innerProject = (LogicalProject) call.rel(1); + var source = call.rel(2); + var builder = call.builder(); + builder.push(source); + var composedExpressions = new java.util.ArrayList(); + var rexBuilder = builder.getRexBuilder(); + + for (var outerExpr : outerProject.getProjects()) { + var composedExpr = outerExpr.accept(new org.apache.calcite.rex.RexShuttle() { + @Override + public org.apache.calcite.rex.RexNode visitInputRef(org.apache.calcite.rex.RexInputRef inputRef) { + int fieldIndex = inputRef.getIndex(); + if (fieldIndex < innerProject.getProjects().size()) { + return innerProject.getProjects().get(fieldIndex); + } + return inputRef; + } + }); + composedExpressions.add(composedExpr); + } + builder.project(composedExpressions); + + return builder; + } + + public static class ConditionDecomposer { + public static RexNode extractLeftOnlyConditions(RexNode condition, int leftFieldCount, RelOptRuleCall call) { + List leftConditions = new ArrayList<>(); + extractConditionsForSide(condition, leftConditions, 0, leftFieldCount - 1); + if (leftConditions.isEmpty()) return null; + if (leftConditions.size() == 1) return leftConditions.get(0); + return RexUtil.composeConjunction(call.builder().getRexBuilder(), leftConditions); + } + + public static RexNode extractRightOnlyConditions(RexNode condition, int leftFieldCount, int totalFieldCount, RelOptRuleCall call) { + List rightConditions = new ArrayList<>(); + extractConditionsForSide(condition, rightConditions, leftFieldCount, totalFieldCount - 1); + if (rightConditions.isEmpty()) return null; + org.apache.calcite.rex.RexBuilder rexBuilder = call.builder().getRexBuilder(); + List adjustedConditions = new ArrayList<>(); + for (RexNode cond : rightConditions) { + adjustedConditions.add(adjustFieldIndices(cond, -leftFieldCount, rexBuilder)); + } + if (adjustedConditions.size() == 1) return adjustedConditions.get(0); + return RexUtil.composeConjunction(rexBuilder, adjustedConditions); + } + + public static RexNode extractJoinConditions(RexNode condition, int leftFieldCount, int totalFieldCount, RelOptRuleCall call) { + List joinConditions = new ArrayList<>(); + extractCrossTableConditions(condition, joinConditions, leftFieldCount, totalFieldCount); + if (joinConditions.isEmpty()) return null; + if (joinConditions.size() == 1) return joinConditions.get(0); + return RexUtil.composeConjunction(call.builder().getRexBuilder(), joinConditions); + } + + private static void extractConditionsForSide(RexNode condition, List result, int minField, int maxField) { + if (condition instanceof RexCall call && call.getOperator().getKind() == org.apache.calcite.sql.SqlKind.AND) { + for (RexNode operand : call.getOperands()) { + extractConditionsForSide(operand, result, minField, maxField); + } + } else if (referencesOnlyFields(condition, minField, maxField)) { + result.add(condition); + } + } + + private static void extractCrossTableConditions(RexNode condition, List result, int leftFieldCount, int totalFieldCount) { + if (condition instanceof RexCall call && call.getOperator().getKind() == org.apache.calcite.sql.SqlKind.AND) { + for (RexNode operand : call.getOperands()) { + extractCrossTableConditions(operand, result, leftFieldCount, totalFieldCount); + } + } else if (referencesBothSides(condition, leftFieldCount, totalFieldCount)) { + result.add(condition); + } + } + + private static boolean referencesOnlyFields(RexNode condition, int minField, int maxField) { + Set fields = new HashSet<>(); + collectFieldReferences(condition, fields); + return !fields.isEmpty() && fields.stream().allMatch(f -> f >= minField && f <= maxField); + } + + private static boolean referencesBothSides(RexNode condition, int leftFieldCount, int totalFieldCount) { + Set fields = new HashSet<>(); + collectFieldReferences(condition, fields); + boolean hasLeft = fields.stream().anyMatch(f -> f < leftFieldCount); + boolean hasRight = fields.stream().anyMatch(f -> f >= leftFieldCount && f < totalFieldCount); + return hasLeft && hasRight; + } + + private static void collectFieldReferences(RexNode node, Set fields) { + if (node instanceof RexInputRef inputRef) { + fields.add(inputRef.getIndex()); + } else if (node instanceof RexCall call) { + for (RexNode operand : call.getOperands()) { + collectFieldReferences(operand, fields); + } + } + } + + private static RexNode adjustFieldIndices(RexNode node, int offset, org.apache.calcite.rex.RexBuilder rexBuilder) { + if (node instanceof RexInputRef inputRef) { + return rexBuilder.makeInputRef(inputRef.getType(), inputRef.getIndex() + offset); + } else if (node instanceof RexCall call) { + List newOperands = new ArrayList<>(); + for (RexNode operand : call.getOperands()) { + newOperands.add(adjustFieldIndices(operand, offset, rexBuilder)); + } + return rexBuilder.makeCall(call.getOperator(), newOperands); + } + return node; + } + } + + public static org.apache.calcite.tools.RelBuilder extractProjectForAggregate(RelOptRuleCall call) { + var builder = call.builder(); + LogicalAggregate aggregate = (LogicalAggregate) call.rel(0); + RelNode input = call.rel(1); + Set usedFields = new HashSet<>(); + for (int field : aggregate.getGroupSet()) { + usedFields.add(field); + } + for (AggregateCall aggCall : aggregate.getAggCallList()) { + for (int field : aggCall.getArgList()) { + usedFields.add(field); + } + if (aggCall.filterArg >= 0) { + usedFields.add(aggCall.filterArg); + } + } + List sortedFields = new ArrayList<>(usedFields); + Collections.sort(sortedFields); + Map fieldMapping = new HashMap<>(); + for (int i = 0; i < sortedFields.size(); i++) { + fieldMapping.put(sortedFields.get(i), i); + } + builder.push(input); + List projectedFields = new ArrayList<>(); + for (int field : sortedFields) { + projectedFields.add(builder.field(field)); + } + builder.project(projectedFields); + ImmutableBitSet.Builder newGroupSet = ImmutableBitSet.builder(); + for (int field : aggregate.getGroupSet()) { + newGroupSet.set(fieldMapping.get(field)); + } + + List newAggCalls = new ArrayList<>(); + for (AggregateCall aggCall : aggregate.getAggCallList()) { + List newArgList = new ArrayList<>(); + for (int field : aggCall.getArgList()) { + newArgList.add(fieldMapping.get(field)); + } + int newFilterArg = aggCall.filterArg >= 0 ? fieldMapping.get(aggCall.filterArg) : -1; + + newAggCalls.add(aggCall.adaptTo( + builder.peek(), + newArgList, + newFilterArg, + aggregate.getGroupCount(), + aggregate.getGroupCount() + )); + } + + builder.aggregate( + builder.groupKey(newGroupSet.build()), + newAggCalls + ); + + return builder; + } +} \ No newline at end of file diff --git a/src/main/java/org/qed/Generated/EmptyConfig.java b/src/main/java/org/qed/Backends/Calcite/EmptyConfig.java similarity index 96% rename from src/main/java/org/qed/Generated/EmptyConfig.java rename to src/main/java/org/qed/Backends/Calcite/EmptyConfig.java index d784cfe..d981492 100644 --- a/src/main/java/org/qed/Generated/EmptyConfig.java +++ b/src/main/java/org/qed/Backends/Calcite/EmptyConfig.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite; import org.apache.calcite.plan.RelRule; import org.apache.calcite.rel.RelNode; diff --git a/src/main/java/org/qed/Generated/AggregateExtractProject.java b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateExtractProject.java similarity index 92% rename from src/main/java/org/qed/Generated/AggregateExtractProject.java rename to src/main/java/org/qed/Backends/Calcite/Generated/AggregateExtractProject.java index 4cb5558..66c7691 100644 --- a/src/main/java/org/qed/Generated/AggregateExtractProject.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateExtractProject.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class AggregateExtractProject extends RelRule { protected AggregateExtractProject(Config config) { diff --git a/src/main/java/org/qed/Generated/AggregateFilterTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateFilterTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/AggregateFilterTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/AggregateFilterTranspose.java index 4e83d35..af33b35 100644 --- a/src/main/java/org/qed/Generated/AggregateFilterTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateFilterTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class AggregateFilterTranspose extends RelRule { protected AggregateFilterTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/AggregateProjectMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateProjectMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/AggregateProjectMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/AggregateProjectMerge.java index a46f3c2..2c2fa7c 100644 --- a/src/main/java/org/qed/Generated/AggregateProjectMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/AggregateProjectMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class AggregateProjectMerge extends RelRule { protected AggregateProjectMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterAggregateTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterAggregateTranspose.java similarity index 94% rename from src/main/java/org/qed/Generated/FilterAggregateTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterAggregateTranspose.java index 4590589..4264d2b 100644 --- a/src/main/java/org/qed/Generated/FilterAggregateTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterAggregateTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterAggregateTranspose extends RelRule { protected FilterAggregateTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterIntoJoin.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterIntoJoin.java similarity index 93% rename from src/main/java/org/qed/Generated/FilterIntoJoin.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterIntoJoin.java index af22f04..2d5a2c0 100644 --- a/src/main/java/org/qed/Generated/FilterIntoJoin.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterIntoJoin.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterIntoJoin extends RelRule { protected FilterIntoJoin(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/FilterMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterMerge.java index ab9f5ba..3a61f9a 100644 --- a/src/main/java/org/qed/Generated/FilterMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterMerge extends RelRule { protected FilterMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterProjectTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterProjectTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/FilterProjectTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterProjectTranspose.java index 2e39d2f..a3faea3 100644 --- a/src/main/java/org/qed/Generated/FilterProjectTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterProjectTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterProjectTranspose extends RelRule { protected FilterProjectTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterReduceFalse.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceFalse.java similarity index 91% rename from src/main/java/org/qed/Generated/FilterReduceFalse.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceFalse.java index 8aa9901..39fae06 100644 --- a/src/main/java/org/qed/Generated/FilterReduceFalse.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceFalse.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterReduceFalse extends RelRule { protected FilterReduceFalse(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterReduceTrue.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceTrue.java similarity index 91% rename from src/main/java/org/qed/Generated/FilterReduceTrue.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceTrue.java index 0da8d36..bb34e6c 100644 --- a/src/main/java/org/qed/Generated/FilterReduceTrue.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterReduceTrue.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterReduceTrue extends RelRule { protected FilterReduceTrue(Config config) { diff --git a/src/main/java/org/qed/Generated/FilterSetOpTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/FilterSetOpTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/FilterSetOpTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/FilterSetOpTranspose.java index aecdedf..bd2d3b2 100644 --- a/src/main/java/org/qed/Generated/FilterSetOpTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/FilterSetOpTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class FilterSetOpTranspose extends RelRule { protected FilterSetOpTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/IntersectMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/IntersectMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/IntersectMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/IntersectMerge.java index 3351323..217447f 100644 --- a/src/main/java/org/qed/Generated/IntersectMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/IntersectMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class IntersectMerge extends RelRule { protected IntersectMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinAddRedundantSemiJoin.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinAddRedundantSemiJoin.java similarity index 93% rename from src/main/java/org/qed/Generated/JoinAddRedundantSemiJoin.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinAddRedundantSemiJoin.java index d896ee5..7e99200 100644 --- a/src/main/java/org/qed/Generated/JoinAddRedundantSemiJoin.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinAddRedundantSemiJoin.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinAddRedundantSemiJoin extends RelRule { protected JoinAddRedundantSemiJoin(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinCommute.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinCommute.java similarity index 96% rename from src/main/java/org/qed/Generated/JoinCommute.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinCommute.java index 1fc837f..ca57631 100644 --- a/src/main/java/org/qed/Generated/JoinCommute.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinCommute.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinCommute extends RelRule { protected JoinCommute(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinConditionPush.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinConditionPush.java similarity index 95% rename from src/main/java/org/qed/Generated/JoinConditionPush.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinConditionPush.java index e1ea60a..ab01cd5 100644 --- a/src/main/java/org/qed/Generated/JoinConditionPush.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinConditionPush.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinConditionPush extends RelRule { protected JoinConditionPush(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinExtractFilter.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinExtractFilter.java similarity index 92% rename from src/main/java/org/qed/Generated/JoinExtractFilter.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinExtractFilter.java index a54cccf..a6b16ce 100644 --- a/src/main/java/org/qed/Generated/JoinExtractFilter.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinExtractFilter.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinExtractFilter extends RelRule { protected JoinExtractFilter(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinPushTransitivePredicates.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinPushTransitivePredicates.java similarity index 93% rename from src/main/java/org/qed/Generated/JoinPushTransitivePredicates.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinPushTransitivePredicates.java index 5668bf5..8bc9c85 100644 --- a/src/main/java/org/qed/Generated/JoinPushTransitivePredicates.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinPushTransitivePredicates.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinPushTransitivePredicates extends RelRule { protected JoinPushTransitivePredicates(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinReduceFalse.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceFalse.java similarity index 92% rename from src/main/java/org/qed/Generated/JoinReduceFalse.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceFalse.java index d619782..8c6250e 100644 --- a/src/main/java/org/qed/Generated/JoinReduceFalse.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceFalse.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -7,6 +7,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinReduceFalse extends RelRule { protected JoinReduceFalse(Config config) { diff --git a/src/main/java/org/qed/Generated/JoinReduceTrue.java b/src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceTrue.java similarity index 92% rename from src/main/java/org/qed/Generated/JoinReduceTrue.java rename to src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceTrue.java index c68d96b..e48b9f2 100644 --- a/src/main/java/org/qed/Generated/JoinReduceTrue.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/JoinReduceTrue.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -7,6 +7,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class JoinReduceTrue extends RelRule { protected JoinReduceTrue(Config config) { diff --git a/src/main/java/org/qed/Generated/MinusMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/MinusMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/MinusMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/MinusMerge.java index f54e5bb..f18ab7d 100644 --- a/src/main/java/org/qed/Generated/MinusMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/MinusMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class MinusMerge extends RelRule { protected MinusMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/ProjectFilterTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/ProjectFilterTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/ProjectFilterTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/ProjectFilterTranspose.java index a92ad8d..c15b233 100644 --- a/src/main/java/org/qed/Generated/ProjectFilterTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/ProjectFilterTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class ProjectFilterTranspose extends RelRule { protected ProjectFilterTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/ProjectMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/ProjectMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/ProjectMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/ProjectMerge.java index 565a3c9..d3c356f 100644 --- a/src/main/java/org/qed/Generated/ProjectMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/ProjectMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class ProjectMerge extends RelRule { protected ProjectMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneEmptyFilter.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyFilter.java similarity index 91% rename from src/main/java/org/qed/Generated/PruneEmptyFilter.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyFilter.java index 743107b..8adfccc 100644 --- a/src/main/java/org/qed/Generated/PruneEmptyFilter.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyFilter.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneEmptyFilter extends RelRule { protected PruneEmptyFilter(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneEmptyIntersect.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyIntersect.java similarity index 92% rename from src/main/java/org/qed/Generated/PruneEmptyIntersect.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyIntersect.java index 813d188..519e9eb 100644 --- a/src/main/java/org/qed/Generated/PruneEmptyIntersect.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyIntersect.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneEmptyIntersect extends RelRule { protected PruneEmptyIntersect(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneEmptyMinus.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyMinus.java similarity index 91% rename from src/main/java/org/qed/Generated/PruneEmptyMinus.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyMinus.java index 780e430..78d0ed9 100644 --- a/src/main/java/org/qed/Generated/PruneEmptyMinus.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyMinus.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneEmptyMinus extends RelRule { protected PruneEmptyMinus(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneEmptyProject.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyProject.java similarity index 91% rename from src/main/java/org/qed/Generated/PruneEmptyProject.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyProject.java index 5873379..98fa167 100644 --- a/src/main/java/org/qed/Generated/PruneEmptyProject.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyProject.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneEmptyProject extends RelRule { protected PruneEmptyProject(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneEmptyUnion.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyUnion.java similarity index 91% rename from src/main/java/org/qed/Generated/PruneEmptyUnion.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyUnion.java index 7f6cdd1..d827fcd 100644 --- a/src/main/java/org/qed/Generated/PruneEmptyUnion.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneEmptyUnion.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneEmptyUnion extends RelRule { protected PruneEmptyUnion(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneLeftEmptyJoin.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneLeftEmptyJoin.java similarity index 92% rename from src/main/java/org/qed/Generated/PruneLeftEmptyJoin.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneLeftEmptyJoin.java index f6a1fed..fa6c378 100644 --- a/src/main/java/org/qed/Generated/PruneLeftEmptyJoin.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneLeftEmptyJoin.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneLeftEmptyJoin extends RelRule { protected PruneLeftEmptyJoin(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneRightEmptyJoin.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneRightEmptyJoin.java similarity index 92% rename from src/main/java/org/qed/Generated/PruneRightEmptyJoin.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneRightEmptyJoin.java index f5da979..26a7a56 100644 --- a/src/main/java/org/qed/Generated/PruneRightEmptyJoin.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneRightEmptyJoin.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneRightEmptyJoin extends RelRule { protected PruneRightEmptyJoin(Config config) { diff --git a/src/main/java/org/qed/Generated/PruneZeroRowsTable.java b/src/main/java/org/qed/Backends/Calcite/Generated/PruneZeroRowsTable.java similarity index 91% rename from src/main/java/org/qed/Generated/PruneZeroRowsTable.java rename to src/main/java/org/qed/Backends/Calcite/Generated/PruneZeroRowsTable.java index 6bbc0b8..e0ef0fc 100644 --- a/src/main/java/org/qed/Generated/PruneZeroRowsTable.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/PruneZeroRowsTable.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class PruneZeroRowsTable extends RelRule { protected PruneZeroRowsTable(Config config) { diff --git a/src/main/java/org/qed/Generated/SemiJoinFilterTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinFilterTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/SemiJoinFilterTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinFilterTranspose.java index 5979dfa..9b3f8b2 100644 --- a/src/main/java/org/qed/Generated/SemiJoinFilterTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinFilterTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class SemiJoinFilterTranspose extends RelRule { protected SemiJoinFilterTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/SemiJoinJoinTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinJoinTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/SemiJoinJoinTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinJoinTranspose.java index 3c5d349..387bcef 100644 --- a/src/main/java/org/qed/Generated/SemiJoinJoinTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinJoinTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class SemiJoinJoinTranspose extends RelRule { protected SemiJoinJoinTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/SemiJoinProjectTranspose.java b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinProjectTranspose.java similarity index 93% rename from src/main/java/org/qed/Generated/SemiJoinProjectTranspose.java rename to src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinProjectTranspose.java index 3d2ec28..6915a02 100644 --- a/src/main/java/org/qed/Generated/SemiJoinProjectTranspose.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinProjectTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class SemiJoinProjectTranspose extends RelRule { protected SemiJoinProjectTranspose(Config config) { diff --git a/src/main/java/org/qed/Generated/SemiJoinRemove.java b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinRemove.java similarity index 91% rename from src/main/java/org/qed/Generated/SemiJoinRemove.java rename to src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinRemove.java index 332e961..7aa5eaf 100644 --- a/src/main/java/org/qed/Generated/SemiJoinRemove.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/SemiJoinRemove.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class SemiJoinRemove extends RelRule { protected SemiJoinRemove(Config config) { diff --git a/src/main/java/org/qed/Generated/UnionMerge.java b/src/main/java/org/qed/Backends/Calcite/Generated/UnionMerge.java similarity index 92% rename from src/main/java/org/qed/Generated/UnionMerge.java rename to src/main/java/org/qed/Backends/Calcite/Generated/UnionMerge.java index 0eeafd5..4effcbb 100644 --- a/src/main/java/org/qed/Generated/UnionMerge.java +++ b/src/main/java/org/qed/Backends/Calcite/Generated/UnionMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated; +package org.qed.Backends.Calcite.Generated; import org.apache.calcite.plan.RelOptRuleCall; import org.apache.calcite.plan.RelRule; @@ -6,6 +6,7 @@ import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.rel.logical.*; +import org.qed.Backends.Calcite.EmptyConfig; public class UnionMerge extends RelRule { protected UnionMerge(Config config) { diff --git a/src/main/java/org/qed/Generated/Tests/AggregateExtractProjectTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateExtractProjectTest.java similarity index 90% rename from src/main/java/org/qed/Generated/Tests/AggregateExtractProjectTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/AggregateExtractProjectTest.java index 2ed3806..63d230f 100644 --- a/src/main/java/org/qed/Generated/Tests/AggregateExtractProjectTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateExtractProjectTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -47,7 +47,7 @@ public static void runTest() { ) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.AggregateExtractProject.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.AggregateExtractProject.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/AggregateFilterTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateFilterTransposeTest.java similarity index 91% rename from src/main/java/org/qed/Generated/Tests/AggregateFilterTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/AggregateFilterTransposeTest.java index c841dae..c761c3a 100644 --- a/src/main/java/org/qed/Generated/Tests/AggregateFilterTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateFilterTransposeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -47,7 +47,7 @@ public static void runTest() { .build(); var runner = CalciteTester.loadRules( - org.qed.Generated.AggregateFilterTranspose.Config.DEFAULT.toRule() + org.qed.Backends.Calcite.Generated.AggregateFilterTranspose.Config.DEFAULT.toRule() ); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Backends/Calcite/Tests/AggregateProjectMergeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateProjectMergeTest.java new file mode 100644 index 0000000..dd4dfcc --- /dev/null +++ b/src/main/java/org/qed/Backends/Calcite/Tests/AggregateProjectMergeTest.java @@ -0,0 +1,72 @@ +package org.qed.Backends.Calcite.Tests; + +import kala.collection.Seq; +import kala.tuple.Tuple; +import org.qed.Backends.Calcite.CalciteTester; +import org.qed.RelType; +import org.qed.RuleBuilder; + +public class AggregateProjectMergeTest { + + public static void runTest() { + var tester = new CalciteTester(); + var builder = RuleBuilder.create(); + var empTable = builder.createQedTable(Seq.of( + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("DATE", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) + )); + builder.addTable(empTable); + + var empScan = builder.scan(empTable.getName()).build(); + + var before = builder + .push(empScan) + .project( + builder.field(7), + builder.field(0), + builder.field(5) + ) + .aggregate( + builder.groupKey(builder.field(0), builder.field(1)), + builder.sum(builder.field(2)) + ) + .project( + builder.field(0), + builder.field(2), + builder.field(1) + ) + .build(); + + var after = builder + .push(empScan) + .aggregate( + builder.groupKey(builder.field(0), builder.field(7)), + builder.sum(builder.field(5)) + ) + .project( + builder.field(1), + builder.field(0), + builder.field(2) + ) + .project( + builder.field(0), + builder.field(2), + builder.field(1) + ) + .build(); + + var runner = CalciteTester.loadRules(org.qed.Backends.Calcite.Generated.AggregateProjectMerge.Config.DEFAULT.toRule(), org.qed.Backends.Calcite.Generated.ProjectMerge.Config.DEFAULT.toRule()); + tester.verify(runner, before, after); + } + + public static void main(String[] args) { + System.out.println("Running AggregateProjectMerge comprehensive test..."); + runTest(); + } +} \ No newline at end of file diff --git a/src/main/java/org/qed/Generated/Tests/FilterAggregateTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/FilterAggregateTransposeTest.java similarity index 73% rename from src/main/java/org/qed/Generated/Tests/FilterAggregateTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/FilterAggregateTransposeTest.java index 3e19148..4754cce 100644 --- a/src/main/java/org/qed/Generated/Tests/FilterAggregateTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/FilterAggregateTransposeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -13,16 +13,15 @@ public static void runTest() { var builder = RuleBuilder.create(); var sourceTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // ID (index 0) - Tuple.of(RelType.fromString("VARCHAR", true), false), // CATEGORY1 (index 1) - Tuple.of(RelType.fromString("VARCHAR", true), false), // CATEGORY2 (index 2) - Tuple.of(RelType.fromString("DECIMAL", true), false) // AMOUNT (index 3) + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false) )); builder.addTable(sourceTable); var sourceScan = builder.scan(sourceTable.getName()).build(); - - // Before: Filter after aggregate (HAVING clause) + var before = builder .push(sourceScan) .aggregate( @@ -31,16 +30,14 @@ public static void runTest() { ) .filter(builder.call( builder.genericPredicateOp("pred", true), - builder.field(0), builder.field(1) // Filter on grouped columns (post-aggregate positions) + builder.field(0), builder.field(1) )) .build(); - - // After: Push filter down before aggregate (WHERE clause) var after = builder .push(sourceScan) .filter(builder.call( builder.genericPredicateOp("pred", true), - builder.field(1), builder.field(2) // Filter on original columns (pre-aggregate positions) + builder.field(1), builder.field(2) )) .aggregate( builder.groupKey(builder.field(1), builder.field(2)), @@ -49,7 +46,7 @@ public static void runTest() { .build(); var runner = CalciteTester.loadRules( - org.qed.Generated.FilterAggregateTranspose.Config.DEFAULT.toRule() + org.qed.Backends.Calcite.Generated.FilterAggregateTranspose.Config.DEFAULT.toRule() ); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/FilterIntoJoinTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/FilterIntoJoinTest.java similarity index 86% rename from src/main/java/org/qed/Generated/Tests/FilterIntoJoinTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/FilterIntoJoinTest.java index f8fef01..368013e 100644 --- a/src/main/java/org/qed/Generated/Tests/FilterIntoJoinTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/FilterIntoJoinTest.java @@ -1,13 +1,12 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.FilterIntoJoin; import org.qed.RuleBuilder; public class FilterIntoJoinTest { @@ -31,7 +30,7 @@ public static void runTest() { builder.call(builder.genericPredicateOp("pred", true), builder.joinFields()))) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.FilterIntoJoin.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.FilterIntoJoin.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/FilterMergeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/FilterMergeTest.java similarity index 86% rename from src/main/java/org/qed/Generated/Tests/FilterMergeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/FilterMergeTest.java index 0e40d00..d449aa1 100644 --- a/src/main/java/org/qed/Generated/Tests/FilterMergeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/FilterMergeTest.java @@ -1,9 +1,9 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -25,7 +25,7 @@ public static void runTest() { builder.call(builder.genericPredicateOp("outer", true), builder.fields()))) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.FilterMerge.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.FilterMerge.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/FilterProjectTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/FilterProjectTransposeTest.java similarity index 63% rename from src/main/java/org/qed/Generated/Tests/FilterProjectTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/FilterProjectTransposeTest.java index 8797dc8..d4899fb 100644 --- a/src/main/java/org/qed/Generated/Tests/FilterProjectTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/FilterProjectTransposeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -11,29 +11,25 @@ public class FilterProjectTransposeTest { public static void runTest() { var tester = new CalciteTester(); var builder = RuleBuilder.create(); - - // Create table with 3 columns: id, salary, dept_id var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // id (col 0) - Tuple.of(RelType.fromString("INTEGER", true), false), // salary (col 1) - Tuple.of(RelType.fromString("INTEGER", true), false) // dept_id (col 2) + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); var scan = builder.scan(table.getName()).build(); - // Project: SELECT salary, dept_id (reordered columns) - // Filter: WHERE salary > 50000 AND dept_id = 5 var before = builder .push(scan) .project( - builder.field(1), // salary -> position 0 in projection - builder.field(2) // dept_id -> position 1 in projection + builder.field(1), + builder.field(2) ) .filter( builder.and( - builder.greaterThan(builder.field(0), builder.literal(50000)), // projected salary > 50000 - builder.equals(builder.field(1), builder.literal(5)) // projected dept_id = 5 + builder.greaterThan(builder.field(0), builder.literal(50000)), + builder.equals(builder.field(1), builder.literal(5)) ) ) .build(); @@ -42,17 +38,17 @@ public static void runTest() { .push(scan) .filter( builder.and( - builder.greaterThan(builder.field(1), builder.literal(50000)), // table salary > 50000 - builder.equals(builder.field(2), builder.literal(5)) // table dept_id = 5 + builder.greaterThan(builder.field(1), builder.literal(50000)), + builder.equals(builder.field(2), builder.literal(5)) ) ) .project( - builder.field(1), // salary - builder.field(2) // dept_id + builder.field(1), + builder.field(2) ) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.FilterProjectTranspose.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.FilterProjectTranspose.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/FilterSetOpTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/FilterSetOpTransposeTest.java similarity index 86% rename from src/main/java/org/qed/Generated/Tests/FilterSetOpTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/FilterSetOpTransposeTest.java index 488b474..6aae255 100644 --- a/src/main/java/org/qed/Generated/Tests/FilterSetOpTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/FilterSetOpTransposeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -26,7 +26,7 @@ public static void runTest() { var filteredScan2 = builder.push(scan2).filter(builder.call(builder.genericPredicateOp("filter", true), builder.fields())).build(); var after = builder.push(filteredScan1).push(filteredScan2).union(false).build(); - var runner = CalciteTester.loadRule(org.qed.Generated.FilterSetOpTranspose.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.FilterSetOpTranspose.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/IntersectMergeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/IntersectMergeTest.java similarity index 84% rename from src/main/java/org/qed/Generated/Tests/IntersectMergeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/IntersectMergeTest.java index ff4093d..a12daf6 100644 --- a/src/main/java/org/qed/Generated/Tests/IntersectMergeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/IntersectMergeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -25,7 +25,7 @@ public static void runTest() { var after = builder.push(scan1).push(scan2).push(scan3).intersect(false, 3).build(); - var runner = CalciteTester.loadRule(org.qed.Generated.IntersectMerge.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.IntersectMerge.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/JoinCommuteTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/JoinCommuteTest.java similarity index 52% rename from src/main/java/org/qed/Generated/Tests/JoinCommuteTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/JoinCommuteTest.java index c6d0203..a832a67 100644 --- a/src/main/java/org/qed/Generated/Tests/JoinCommuteTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/JoinCommuteTest.java @@ -1,9 +1,9 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -12,29 +12,26 @@ public class JoinCommuteTest { public static void runTest() { var tester = new CalciteTester(); var builder = RuleBuilder.create(); - - // Create EMP table (8 columns like the real Calcite test) + var empTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // EMPNO - Tuple.of(RelType.fromString("VARCHAR", true), false), // ENAME - Tuple.of(RelType.fromString("VARCHAR", true), false), // JOB - Tuple.of(RelType.fromString("INTEGER", true), false), // MGR - Tuple.of(RelType.fromString("DATE", true), false), // HIREDATE - Tuple.of(RelType.fromString("DECIMAL", true), false), // SAL - Tuple.of(RelType.fromString("DECIMAL", true), false), // COMM - Tuple.of(RelType.fromString("INTEGER", true), false) // DEPTNO + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("DATE", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(empTable); - - // Create DEPT table (3 columns like the real Calcite test) + var deptTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // DEPTNO - Tuple.of(RelType.fromString("VARCHAR", true), false), // DNAME - Tuple.of(RelType.fromString("VARCHAR", true), false) // LOC + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false) )); builder.addTable(deptTable); - - // Build the "before" pattern: EMP JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO + var empScan = builder.scan(empTable.getName()).build(); var deptScan = builder.scan(deptTable.getName()).build(); @@ -42,38 +39,34 @@ public static void runTest() { .push(empScan) .push(deptScan) .join(JoinRelType.INNER, builder.call(builder.genericPredicateOp("equals", true), - builder.field(2, 0, 7), // EMP.DEPTNO (8th column, index 7) - builder.field(2, 1, 0) // DEPT.DEPTNO (1st column, index 0) + builder.field(2, 0, 7), + builder.field(2, 1, 0) )) .build(); - - // Build the "after" pattern: DEPT JOIN EMP ON DEPT.DEPTNO = EMP.DEPTNO - // followed by projection to restore original column order + var after = builder .push(deptScan) .push(empScan) .join(JoinRelType.INNER, builder.call(builder.genericPredicateOp("equals", true), - builder.field(2, 1, 7), // EMP.DEPTNO (now at input 1, field 7) - builder.field(2, 0, 0) // DEPT.DEPTNO (now at input 0, field 0) + builder.field(2, 1, 7), + builder.field(2, 0, 0) )) .project( - // EMP columns first (now at positions 3-10 in the swapped join) - builder.field(3), // EMPNO - builder.field(4), // ENAME - builder.field(5), // JOB - builder.field(6), // MGR - builder.field(7), // HIREDATE - builder.field(8), // SAL - builder.field(9), // COMM - builder.field(10), // DEPTNO - // DEPT columns second (now at positions 0-2 in the swapped join) - builder.field(0), // DEPTNO0 - builder.field(1), // DNAME - builder.field(2) // LOC + builder.field(3), + builder.field(4), + builder.field(5), + builder.field(6), + builder.field(7), + builder.field(8), + builder.field(9), + builder.field(10), + builder.field(0), + builder.field(1), + builder.field(2) ) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinCommute.Config.DEFAULT.toRule(), 1); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinCommute.Config.DEFAULT.toRule(), 1); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/JoinConditionPushTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/JoinConditionPushTest.java similarity index 57% rename from src/main/java/org/qed/Generated/Tests/JoinConditionPushTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/JoinConditionPushTest.java index 9356700..ff2af1f 100644 --- a/src/main/java/org/qed/Generated/Tests/JoinConditionPushTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/JoinConditionPushTest.java @@ -1,10 +1,10 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -13,76 +13,64 @@ public class JoinConditionPushTest { public static void runTest() { var tester = new CalciteTester(); var builder = RuleBuilder.create(); - - // Create EMP table (simplified version with key fields) + var empTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // EMPNO - Tuple.of(RelType.fromString("VARCHAR", true), false), // ENAME - Tuple.of(RelType.fromString("INTEGER", true), false) // DEPTNO + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(empTable); - - // Create DEPT table + var deptTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // DEPTNO - Tuple.of(RelType.fromString("VARCHAR", true), false) // DNAME + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false) )); builder.addTable(deptTable); var empScan = builder.scan(empTable.getName()).build(); var deptScan = builder.scan(deptTable.getName()).build(); - - // Build the "before" pattern: - // JOIN with complex condition: joinCond AND leftCond AND rightCond + var before = builder .push(empScan) .push(deptScan) .join(JoinRelType.INNER, builder.call(SqlStdOperatorTable.AND, - // Cross-table join condition: emp.deptno = dept.deptno builder.call(builder.genericPredicateOp("joinCond", true), - builder.field(2, 0, 2), // EMP.DEPTNO (field 2 of left input) - builder.field(2, 1, 0) // DEPT.DEPTNO (field 0 of right input) + builder.field(2, 0, 2), + builder.field(2, 1, 0) ), - // Left-only condition: emp.empno condition builder.call(builder.genericPredicateOp("leftCond", true), - builder.field(2, 0, 0) // EMP.EMPNO (field 0 of left input) + builder.field(2, 0, 0) ), - // Right-only condition: dept.deptno condition builder.call(builder.genericPredicateOp("rightCond", true), - builder.field(2, 1, 0) // DEPT.DEPTNO (field 0 of right input) + builder.field(2, 1, 0) ) )) .build(); - - // Build the "after" pattern: - // JOIN with only cross-table condition, filters pushed down + var after = builder .push( - // Left side: filtered EMP table builder.push(empScan) .filter(builder.call(builder.genericPredicateOp("leftCond", true), - builder.field(0) // EMP.EMPNO (field 0 in filter context) + builder.field(0) )) .build() ) .push( - // Right side: filtered DEPT table builder.push(deptScan) .filter(builder.call(builder.genericPredicateOp("rightCond", true), - builder.field(0) // DEPT.DEPTNO (field 0 in filter context) + builder.field(0) )) .build() ) - .join(JoinRelType.INNER, - // Only the cross-table join condition remains + .join(JoinRelType.INNER, builder.call(builder.genericPredicateOp("joinCond", true), - builder.field(2, 0, 2), // EMP.DEPTNO (field 2 of left input) - builder.field(2, 1, 0) // DEPT.DEPTNO (field 0 of right input) + builder.field(2, 0, 2), + builder.field(2, 1, 0) ) ) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinConditionPush.Config.DEFAULT.toRule(), 1); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinConditionPush.Config.DEFAULT.toRule(), 1); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/JoinExtractFilterTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/JoinExtractFilterTest.java similarity index 88% rename from src/main/java/org/qed/Generated/Tests/JoinExtractFilterTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/JoinExtractFilterTest.java index db2138a..a2ec839 100644 --- a/src/main/java/org/qed/Generated/Tests/JoinExtractFilterTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/JoinExtractFilterTest.java @@ -1,9 +1,9 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -35,7 +35,7 @@ public static void runTest() { .filter(builder.call(builder.genericPredicateOp("join", true), builder.field(0), builder.field(1))) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinExtractFilter.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinExtractFilter.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/JoinPushTransitivePredicatesTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/JoinPushTransitivePredicatesTest.java similarity index 87% rename from src/main/java/org/qed/Generated/Tests/JoinPushTransitivePredicatesTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/JoinPushTransitivePredicatesTest.java index 3da47c7..5d0c97c 100644 --- a/src/main/java/org/qed/Generated/Tests/JoinPushTransitivePredicatesTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/JoinPushTransitivePredicatesTest.java @@ -1,10 +1,10 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -30,7 +30,7 @@ public static void runTest() { builder.call(builder.genericPredicateOp("cond2", true), builder.joinFields()))) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinPushTransitivePredicates.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinPushTransitivePredicates.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/MinusMergeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/MinusMergeTest.java similarity index 69% rename from src/main/java/org/qed/Generated/Tests/MinusMergeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/MinusMergeTest.java index bc9985e..71ef13e 100644 --- a/src/main/java/org/qed/Generated/Tests/MinusMergeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/MinusMergeTest.java @@ -1,20 +1,12 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.UnionMerge; import org.qed.RuleBuilder; -/** - * Test for the MinusMerge rule. - */ public class MinusMergeTest { - - /** - * Run test for MinusMerge rule. - */ public static void runTest() { var tester = new CalciteTester(); var builder = RuleBuilder.create(); @@ -26,21 +18,15 @@ public static void runTest() { var scan1 = builder.scan(table.getName()).build(); var scan2 = builder.scan(table.getName()).build(); var scan3 = builder.scan(table.getName()).build(); - - // (A − B) − C + var before = builder.push(scan1).push(scan2).minus(false, 2).push(scan3).minus(false, 2).build(); - // A − (B ∪ C) var union = builder.push(scan2).push(scan3).union(false).build(); var after = builder.push(scan1).push(union).minus(false, 2).build(); - var runner = CalciteTester.loadRule(org.qed.Generated.MinusMerge.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.MinusMerge.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } - - /** - * Main method to run this test independently. - */ public static void main(String[] args) { System.out.println("Running MinusMerge test..."); runTest(); diff --git a/src/main/java/org/qed/Generated/Tests/ProjectFilterTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/ProjectFilterTransposeTest.java similarity index 67% rename from src/main/java/org/qed/Generated/Tests/ProjectFilterTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/ProjectFilterTransposeTest.java index d4065ba..2c8a522 100644 --- a/src/main/java/org/qed/Generated/Tests/ProjectFilterTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/ProjectFilterTransposeTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -10,12 +10,11 @@ public class ProjectFilterTransposeTest { public static void runTest() { var tester = new CalciteTester(); var builder = RuleBuilder.create(); - - // Create table with 3 columns: id, salary, dept_id + var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // id (col 0) - Tuple.of(RelType.fromString("INTEGER", true), false), // salary (col 1) - Tuple.of(RelType.fromString("INTEGER", true), false) // dept_id (col 2) + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); @@ -25,31 +24,31 @@ public static void runTest() { .push(scan) .filter( builder.and( - builder.greaterThan(builder.field(1), builder.literal(50000)), // table salary > 50000 - builder.equals(builder.field(2), builder.literal(5)) // table dept_id = 5 + builder.greaterThan(builder.field(1), builder.literal(50000)), + builder.equals(builder.field(2), builder.literal(5)) ) ) .project( - builder.field(1), // salary - builder.field(2) // dept_id + builder.field(1), + builder.field(2) ) .build(); var after = builder .push(scan) .project( - builder.field(1), // salary -> position 0 in projection - builder.field(2) // dept_id -> position 1 in projection + builder.field(1), + builder.field(2) ) .filter( builder.and( - builder.greaterThan(builder.field(0), builder.literal(50000)), // projected salary > 50000 - builder.equals(builder.field(1), builder.literal(5)) // projected dept_id = 5 + builder.greaterThan(builder.field(0), builder.literal(50000)), + builder.equals(builder.field(1), builder.literal(5)) ) ) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.ProjectFilterTranspose.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.ProjectFilterTranspose.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/SemiJoinFilterTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/SemiJoinFilterTransposeTest.java similarity index 88% rename from src/main/java/org/qed/Generated/Tests/SemiJoinFilterTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/SemiJoinFilterTransposeTest.java index 11e404a..3d73f9c 100644 --- a/src/main/java/org/qed/Generated/Tests/SemiJoinFilterTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/SemiJoinFilterTransposeTest.java @@ -1,11 +1,10 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.SemiJoinFilterTranspose; import org.qed.RuleBuilder; public class SemiJoinFilterTransposeTest { @@ -38,7 +37,7 @@ public static void runTest() { var afterJoinPredicate = builder.equals(builder.field(2, 0, 0), builder.field(2, 1, 0)); var after = builder.join(JoinRelType.SEMI, afterJoinPredicate).build(); - var runner = CalciteTester.loadRule(org.qed.Generated.SemiJoinFilterTranspose.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.SemiJoinFilterTranspose.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests/UnionMergeTest.java b/src/main/java/org/qed/Backends/Calcite/Tests/UnionMergeTest.java similarity index 82% rename from src/main/java/org/qed/Generated/Tests/UnionMergeTest.java rename to src/main/java/org/qed/Backends/Calcite/Tests/UnionMergeTest.java index 3ad7e07..68fdb9d 100644 --- a/src/main/java/org/qed/Generated/Tests/UnionMergeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/Tests/UnionMergeTest.java @@ -1,10 +1,9 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.Tests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.UnionMerge; import org.qed.RuleBuilder; public class UnionMergeTest { @@ -26,7 +25,7 @@ public static void runTest() { var after = builder.push(scan1).push(scan2).push(scan3).union(false, 3).build(); - var runner = CalciteTester.loadRule(org.qed.Generated.UnionMerge.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.UnionMerge.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceFalseTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceFalseTest.java similarity index 85% rename from src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceFalseTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceFalseTest.java index bc274fe..3f1e74b 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceFalseTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceFalseTest.java @@ -1,12 +1,11 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.JoinReduceFalse; import org.qed.RuleBuilder; public class JoinReduceFalseTest { @@ -32,7 +31,7 @@ public static void runTest() { .join(JoinRelType.INNER, builder.literal(false)) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinReduceFalse.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinReduceFalse.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceTrueTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceTrueTest.java similarity index 86% rename from src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceTrueTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceTrueTest.java index 16e6b78..8d72b3e 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/JoinReduceTrueTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/JoinReduceTrueTest.java @@ -1,12 +1,11 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; import org.apache.calcite.sql.fun.SqlStdOperatorTable; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; -import org.qed.Generated.RRuleInstances.JoinReduceTrue; import org.qed.RuleBuilder; public class JoinReduceTrueTest { @@ -32,7 +31,7 @@ public static void runTest() { .join(JoinRelType.INNER, builder.call(builder.genericPredicateOp("join", true), builder.joinFields())) .build(); - var runner = CalciteTester.loadRule(org.qed.Generated.JoinReduceTrue.Config.DEFAULT.toRule()); + var runner = CalciteTester.loadRule(org.qed.Backends.Calcite.Generated.JoinReduceTrue.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyFilterTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyFilterTest.java similarity index 86% rename from src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyFilterTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyFilterTest.java index dde4f6e..322decd 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyFilterTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyFilterTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -34,7 +34,7 @@ public static void runTest() { .build(); var runner = CalciteTester.loadRule( - org.qed.Generated.PruneEmptyFilter.Config.DEFAULT.toRule() + org.qed.Backends.Calcite.Generated.PruneEmptyFilter.Config.DEFAULT.toRule() ); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyMinusTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyMinusTest.java similarity index 79% rename from src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyMinusTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyMinusTest.java index d24d6ad..3d10300 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyMinusTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyMinusTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; import org.apache.calcite.rel.RelNode; @@ -38,10 +38,10 @@ public static void runTest() { .empty() .build(); -// var runner = CalciteTester.loadRule( -// org.qed.Generated.PruneEmptyMinus.Config.DEFAULT.toRule() -// ); -// tester.verify(runner, before, after); + var runner = CalciteTester.loadRule( + org.qed.Backends.Calcite.Generated.PruneEmptyMinus.Config.DEFAULT.toRule() + ); + tester.verify(runner, before, after); } public static void main(String[] args) { diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyProjectTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyProjectTest.java similarity index 83% rename from src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyProjectTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyProjectTest.java index 547da2c..831f516 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyProjectTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyProjectTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -29,7 +29,7 @@ public static void runTest() { .build(); var runner = CalciteTester.loadRule( - org.qed.Generated.PruneEmptyProject.Config.DEFAULT.toRule() + org.qed.Backends.Calcite.Generated.PruneEmptyProject.Config.DEFAULT.toRule() ); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyUnionTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyUnionTest.java similarity index 88% rename from src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyUnionTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyUnionTest.java index dcbbc9d..cb2a966 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/PruneEmptyUnionTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneEmptyUnionTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; import org.apache.calcite.rel.RelNode; @@ -50,7 +50,7 @@ public static void runTest() { .build(); var runner = CalciteTester.loadRule( - org.qed.Generated.PruneEmptyUnion.Config.DEFAULT.toRule() + org.qed.Backends.Calcite.Generated.PruneEmptyUnion.Config.DEFAULT.toRule() ); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/PruneZeroRowsTableTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneZeroRowsTableTest.java similarity index 74% rename from src/main/java/org/qed/Generated/Tests-Trivial/PruneZeroRowsTableTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneZeroRowsTableTest.java index b7a91ed..f05ec29 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/PruneZeroRowsTableTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/PruneZeroRowsTableTest.java @@ -1,8 +1,8 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -27,10 +27,10 @@ public static void runTest() { .empty() .build(); -// var runner = CalciteTester.loadRule( -// org.qed.Generated.PruneZeroRowsTable.Config.DEFAULT.toRule() -// ); -// tester.verify(runner, before, after); + var runner = CalciteTester.loadRule( + org.qed.Backends.Calcite.Generated.PruneZeroRowsTable.Config.DEFAULT.toRule() + ); + tester.verify(runner, before, after); } public static void main(String[] args) { diff --git a/src/main/java/org/qed/Generated/Tests-Trivial/SemiJoinProjectTransposeTest.java b/src/main/java/org/qed/Backends/Calcite/TrivialTests/SemiJoinProjectTransposeTest.java similarity index 90% rename from src/main/java/org/qed/Generated/Tests-Trivial/SemiJoinProjectTransposeTest.java rename to src/main/java/org/qed/Backends/Calcite/TrivialTests/SemiJoinProjectTransposeTest.java index 47d0755..defca6e 100644 --- a/src/main/java/org/qed/Generated/Tests-Trivial/SemiJoinProjectTransposeTest.java +++ b/src/main/java/org/qed/Backends/Calcite/TrivialTests/SemiJoinProjectTransposeTest.java @@ -1,9 +1,9 @@ -package org.qed.Generated.Tests; +package org.qed.Backends.Calcite.TrivialTests; import kala.collection.Seq; import kala.tuple.Tuple; import org.apache.calcite.rel.core.JoinRelType; -import org.qed.Generated.CalciteTester; +import org.qed.Backends.Calcite.CalciteTester; import org.qed.RelType; import org.qed.RuleBuilder; @@ -44,7 +44,7 @@ public static void runTest() { var after = builder.join(JoinRelType.SEMI, afterJoinPred).build(); var runner = CalciteTester.loadRule( - org.qed.Generated.SemiJoinProjectTranspose.Config.DEFAULT.toRule()); + org.qed.Backends.Calcite.Generated.SemiJoinProjectTranspose.Config.DEFAULT.toRule()); tester.verify(runner, before, after); } diff --git a/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java b/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java new file mode 100644 index 0000000..20fc7db --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/CockroachGenerator.java @@ -0,0 +1,618 @@ +package org.qed.Backends.Cockroach; + +import kala.collection.Seq; +import kala.collection.immutable.ImmutableMap; +import org.qed.CodeGenerator; +import org.qed.RelRN; +import org.qed.RexRN; +import java.util.concurrent.atomic.AtomicInteger; + +public class CockroachGenerator implements CodeGenerator { + + @Override + public Env preMatch(String rulename) { + return Env.empty(rulename); + } + + @Override + public Env onMatchScan(Env env, RelRN.Scan scan) { + String varName = env.generateVar("input"); + return env.addBinding(scan.name(), varName) + .focus("$" + varName + ":*"); + } + + @Override + public Env onMatchFilter(Env env, RelRN.Filter filter) { + Env sourceEnv = onMatch(env, filter.source()); + String sourcePattern = sourceEnv.current(); + Env condEnv = onMatch(sourceEnv, filter.cond()); + String condPattern; + if (filter.cond() instanceof RexRN.True) { + String pattern = "(Select\n " + sourcePattern + "\n []\n)"; + return condEnv.setPattern(pattern).focus(pattern); + } else if (filter.cond() instanceof RexRN.False) { + condPattern = condEnv.pattern(); + } else { + condPattern = condEnv.current(); + } + String pattern = "(Select\n " + sourcePattern + "\n " + condPattern + "\n)"; + return condEnv.setPattern(pattern).focus(pattern); + } + + public Env onMatchProject(Env env, RelRN.Project project) { + if (env.rulename.equals("ProjectMerge") && project.source() instanceof RelRN.Project) { + Env outerProjEnv = onMatch(env, project.map()); + String outerProjPattern = outerProjEnv.current(); + RelRN.Project innerProject = (RelRN.Project) project.source(); + Env innerInputEnv = onMatch(outerProjEnv, innerProject.source()); + String innerInputPattern = innerInputEnv.current(); + Env innerProjEnv = onMatch(innerInputEnv, innerProject.map()); + String innerProjPattern = innerProjEnv.current(); + String innerPassthroughVar = innerProjEnv.generateVar("innerPassthrough"); + Env innerPassthroughEnv = innerProjEnv.addBinding("innerPassthrough", innerPassthroughVar); + String outerPassthroughVar = innerPassthroughEnv.generateVar("passthrough"); + Env outerPassthroughEnv = innerPassthroughEnv.addBinding("passthrough", outerPassthroughVar); + String innerProjectPattern = "Project\n " + innerInputPattern + "\n " + innerProjPattern + "\n $" + innerPassthroughVar + ":*"; + String outerProjVar = outerProjPattern.replace(":*", ""); + String innerProjVar = innerProjPattern.replace(":*", ""); + String pattern = "(Project\n $input:(" + innerProjectPattern + ")\n " + outerProjPattern + " &\n (CanMergeProjections " + outerProjVar + " " + innerProjVar + ")\n $" + outerPassthroughVar + ":*\n)"; + return outerPassthroughEnv.setPattern(pattern).focus(pattern); + } + Env sourceEnv = onMatch(env, project.source()); + String sourcePattern = sourceEnv.current(); + Env projEnv = onMatch(sourceEnv, project.map()); + String projPattern = projEnv.current(); + String passthroughVar = projEnv.generateVar("passthrough"); + Env passthroughEnv = projEnv.addBinding("passthrough", passthroughVar); + String pattern = "(Project\n " + sourcePattern + "\n " + projPattern + "\n $" + passthroughVar + ":*\n)"; + return passthroughEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env onMatchJoin(Env env, RelRN.Join join) { + Env leftEnv = onMatch(env, join.left()); + String leftPattern = leftEnv.current(); + Env rightEnv = onMatch(leftEnv, join.right()); + String rightPattern = rightEnv.current(); + Env condEnv = onMatch(rightEnv, join.cond()); + String condPattern = condEnv.current(); + String privateVar = condEnv.generateVar("private"); + Env privateEnv = condEnv.addBinding("private_" + System.identityHashCode(join), privateVar) + .addBinding("last_private", privateVar); + String joinType = getJoinType(join.ty().semantics()); + String pattern = "(" + joinType + "\n " + leftPattern + "\n " + rightPattern + "\n " + condPattern + "\n $" + privateVar + ":*\n)"; + return privateEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformJoin(Env env, RelRN.Join join) { + Env leftEnv = transform(env, join.left()); + String leftPattern = leftEnv.current(); + Env rightEnv = transform(leftEnv, join.right()); + String rightPattern = rightEnv.current(); + Env condEnv = transform(rightEnv, join.cond()); + String condPattern = condEnv.current(); + String privateVar = condEnv.bindings().getOrDefault("private_" + System.identityHashCode(join), + condEnv.bindings().getOrDefault("last_private", "private")); + String joinType = getJoinType(join.ty().semantics()); + if (env.rulename.equals("JoinCommute")) { + String pattern = "(" + joinType + "\n $input_1\n $input_0\n " + condPattern + "\n $" + privateVar + "\n)"; + return condEnv.setPattern(pattern).focus(pattern); + } + String pattern = "(" + joinType + "\n " + leftPattern + "\n " + rightPattern + "\n " + condPattern + "\n $" + privateVar + "\n)"; + return condEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env onMatchUnion(Env env, RelRN.Union union) { + Env currentEnv = env; + Seq sourcePatterns = Seq.empty(); + for (RelRN source : union.sources()) { + Env sourceEnv = onMatch(currentEnv, source); + if (source instanceof RelRN.Union) { + String subPrivate = sourceEnv.bindings().get("union_private"); + if (subPrivate != null) { + sourceEnv = sourceEnv.addBinding("inner_union_private", subPrivate); + } + } + sourcePatterns = sourcePatterns.appended(sourceEnv.current()); + currentEnv = sourceEnv; + } + String privateVar = currentEnv.generateVar("private"); + Env privateEnv = currentEnv.addBinding("union_private", privateVar); + String unionType = union.all() ? "UnionAll" : "Union"; + String pattern; + if (sourcePatterns.size() == 2) { + pattern = "(" + unionType + "\n " + sourcePatterns.get(0) + "\n " + sourcePatterns.get(1) + "\n $" + privateVar + ":*\n)"; + } else { + pattern = buildNestedUnion(unionType, sourcePatterns, privateVar + ":*"); + } + return privateEnv.setPattern(pattern).focus(pattern); + } + + private String buildNestedUnion(String unionType, Seq sources, String privatePattern) { + if (sources.size() == 2) { + return "(" + unionType + "\n " + sources.get(0) + "\n " + sources.get(1) + "\n $" + privatePattern + "\n)"; + } + String first = sources.get(0); + String nested = buildNestedUnion(unionType, sources.drop(1), privatePattern); + return "(" + unionType + "\n " + first + "\n " + nested + "\n $" + privatePattern + "\n)"; + } + + @Override + public Env onMatchIntersect(Env env, RelRN.Intersect intersect) { + Env currentEnv = env; + Seq sourcePatterns = Seq.empty(); + for (RelRN source : intersect.sources()) { + Env sourceEnv = onMatch(currentEnv, source); + if (source instanceof RelRN.Intersect) { + String subPrivate = sourceEnv.bindings().get("intersect_private"); + if (subPrivate != null) { + sourceEnv = sourceEnv.addBinding("inner_intersect_private", subPrivate); + } + } + sourcePatterns = sourcePatterns.appended(sourceEnv.current()); + currentEnv = sourceEnv; + } + String privateVar = currentEnv.generateVar("private"); + Env privateEnv = currentEnv.addBinding("intersect_private", privateVar); + String intersectType = intersect.all() ? "IntersectAll" : "Intersect"; + String pattern; + if (sourcePatterns.size() == 2) { + pattern = "(" + intersectType + "\n " + sourcePatterns.get(0) + "\n " + sourcePatterns.get(1) + "\n $" + privateVar + ":*\n)"; + } else { + pattern = buildNestedIntersect(intersectType, sourcePatterns, privateVar + ":*"); + } + return privateEnv.setPattern(pattern).focus(pattern); + } + + + private String buildNestedIntersect(String intersectType, Seq sources, String privatePattern) { + if (sources.size() == 2) { + return "(" + intersectType + "\n " + sources.get(0) + "\n " + sources.get(1) + "\n $" + privatePattern + "\n)"; + } + String first = sources.get(0); + String nested = buildNestedIntersect(intersectType, sources.drop(1), privatePattern); + return "(" + intersectType + "\n " + first + "\n " + nested + "\n $" + privatePattern + "\n)"; + } + + @Override + public Env onMatchAggregate(Env env, RelRN.Aggregate aggregate) { + Env sourceEnv = onMatch(env, aggregate.source()); + String sourcePattern = sourceEnv.current(); + Env aggsEnv = onMatchAggCalls(sourceEnv, aggregate.aggCalls()); + String aggsPattern = aggsEnv.current(); + Env groupingEnv = onMatchGroupSet(aggsEnv, aggregate.groupSet()); + String groupingPattern = groupingEnv.current(); + String privateVar = groupingEnv.generateVar("private"); + Env privateEnv = groupingEnv.addBinding("aggregate_private", privateVar); + String aggregateType = determineAggregateType(aggregate); + String pattern = "(" + aggregateType + "\n " + sourcePattern + "\n " + aggsPattern + "\n $" + privateVar + ":*\n)"; + return privateEnv.setPattern(pattern).focus(pattern); + } + + private Env onMatchAggCalls(Env env, Seq aggCalls) { + Env currentEnv = env; + Seq aggPatterns = Seq.empty(); + for (RelRN.AggCall aggCall : aggCalls) { + String aggVar = currentEnv.generateVar("agg"); + Env aggEnv = currentEnv.addBinding(aggCall.name(), aggVar); + aggPatterns = aggPatterns.appended("$" + aggVar + ":*"); + currentEnv = aggEnv; + } + String pattern; + if (aggCalls.size() == 1) { + String aggVar = currentEnv.generateVar("aggregations"); + Env boundEnv = currentEnv.addBinding("aggregations", aggVar); + pattern = "$" + aggVar + ":*"; + return boundEnv.setPattern(pattern).focus(pattern); + } else { + pattern = "[" + aggPatterns.joinToString(" ") + "]"; + return currentEnv.setPattern(pattern).focus(pattern); + } + } + + private Env onMatchGroupSet(Env env, Seq groupSet) { + Env currentEnv = env; + Seq groupPatterns = Seq.empty(); + for (RexRN groupCol : groupSet) { + Env groupEnv = onMatch(currentEnv, groupCol); + groupPatterns = groupPatterns.appended(groupEnv.current()); + currentEnv = groupEnv; + } + String pattern = "[" + groupPatterns.joinToString(" ") + "]"; + return currentEnv.setPattern(pattern).focus(pattern); + } + + private String determineAggregateType(RelRN.Aggregate aggregate) { + return "GroupBy"; + } + + @Override + public Env onMatchEmpty(Env env, RelRN.Empty empty) { + String varName = env.generateVar("empty"); + return env.addBinding("empty", varName) + .focus("$" + varName + ":(Values)"); + } + + @Override + public Env onMatchField(Env env, RexRN.Field field) { + String varName = env.generateVar("field"); + return env.addBinding("field_" + field.ordinal(), varName) + .focus("$" + varName + ":*"); + } + + @Override + public Env onMatchPred(Env env, RexRN.Pred pred) { + String varName = env.generateVar("cond"); + return env.addBinding(pred.operator().getName(), varName) + .focus("$" + varName + ":*"); + } + + @Override + public Env onMatchProj(Env env, RexRN.Proj proj) { + String varName = env.generateVar("proj"); + return env.addBinding(proj.operator().getName(), varName) + .focus("$" + varName + ":*"); + } + + public Env onMatchGroupBy(Env env, RexRN.GroupBy groupBy) { + String varName = env.generateVar("groupBy"); + return env.addBinding(groupBy.operator().getName(), varName) + .focus("$" + varName + ":*"); + } + + @Override + public Env onMatchAnd(Env env, RexRN.And and) { + Env currentEnv = env; + Seq operandPatterns = Seq.empty(); + for (RexRN operand : and.sources()) { + Env operandEnv = onMatch(currentEnv, operand); + operandPatterns = operandPatterns.appended(operandEnv.current()); + currentEnv = operandEnv; + } + String pattern = buildNestedAndPattern(operandPatterns); + return currentEnv.setPattern(pattern).focus(pattern); + } + + private String buildNestedAndPattern(Seq operands) { + if (operands.isEmpty()) { + return "(And)"; + } + if (operands.size() == 1) { + return operands.get(0); + } + String left = operands.get(0); + String right = buildNestedAndPattern(operands.drop(1)); + return "(And " + left + " " + right + ")"; + } + + @Override + public Env onMatchTrue(Env env, RexRN literal) { + String varName = env.generateVar("true"); + return env.addBinding("true_" + System.identityHashCode(literal), varName) + .focus("$" + varName + ":(True)") + .setPattern("$" + varName + ":(True)"); + } + + @Override + public Env onMatchFalse(Env env, RexRN literal) { + return env.focus("(False)") + .setPattern("(False)"); + } + + @Override + public Env onMatchCustom(Env env, RexRN custom) { + if (custom instanceof RexRN.GroupBy groupBy) { + return onMatchGroupBy(env, groupBy); + } + return unimplementedOnMatch(env, custom); + } + + @Override + public Env transformScan(Env env, RelRN.Scan scan) { + String varName = env.bindings().getOrDefault(scan.name(), "input"); + String pattern = "$" + varName; + return env.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformFilter(Env env, RelRN.Filter filter) { + if (filter.cond() instanceof RexRN.True) { + return transform(env, filter.source()); + } + if (filter.source() instanceof RelRN.Empty) { + return transform(env, filter.source()); + } + Env sourceEnv = transform(env, filter.source()); + String sourcePattern = sourceEnv.current(); + Env condEnv = transform(sourceEnv, filter.cond()); + String condPattern = condEnv.current(); + String filterPattern; + if (condPattern.startsWith("(ConcatFilters")) { + filterPattern = condPattern; + } else if (condPattern.startsWith("$") && !condPattern.contains(" ")) { + filterPattern = condPattern; + } else { + filterPattern = "[" + condPattern + "]"; + } + String pattern = "(Select\n " + sourcePattern + "\n " + filterPattern + "\n)"; + return condEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformProject(Env env, RelRN.Project project) { + if (env.rulename.equals("ProjectMerge")) { + String pattern = "(Project\n $input_1\n (MergeProjections\n $proj_0\n $proj_2\n $passthrough_4\n )\n (DifferenceCols\n $innerPassthrough_3\n (ProjectionCols $proj_2)\n )\n)"; + return env.setPattern(pattern).focus(pattern); + } + Env sourceEnv = transform(env, project.source()); + String sourcePattern = sourceEnv.current(); + Env projEnv = transform(sourceEnv, project.map()); + String projPattern = projEnv.current(); + String passthroughVar = projEnv.bindings().get("passthrough"); + if (passthroughVar == null) { + passthroughVar = "passthrough"; + } + String pattern = "(Project\n " + sourcePattern + "\n " + projPattern + "\n $" + passthroughVar + "\n)"; + return projEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformUnion(Env env, RelRN.Union union) { + Env currentEnv = env; + Seq sourcePatterns = Seq.empty(); + for (RelRN source : union.sources()) { + Env sourceEnv = transform(currentEnv, source); + sourcePatterns = sourcePatterns.appended(sourceEnv.current()); + currentEnv = sourceEnv; + } + String privateVar = currentEnv.bindings().getOrDefault("union_private", "private"); + String unionType = union.all() ? "UnionAll" : "Union"; + String pattern; + if (sourcePatterns.size() == 2) { + pattern = "(" + unionType + "\n " + sourcePatterns.get(0) + "\n " + sourcePatterns.get(1) + "\n $" + privateVar + "\n)"; + } else { + String nestedPrivate = currentEnv.bindings().getOrDefault("inner_union_private", privateVar); + String nested = buildNestedUnionTransform(unionType, sourcePatterns.drop(1), nestedPrivate); + pattern = "(" + unionType + "\n " + sourcePatterns.get(0) + "\n " + nested + "\n $" + privateVar + "\n)"; + } + return currentEnv.setPattern(pattern).focus(pattern); + } + + private String buildNestedUnionTransform(String unionType, Seq sources, String privateVar) { + if (sources.size() == 2) { + return "(" + unionType + "\n " + sources.get(0) + "\n " + sources.get(1) + "\n $" + privateVar + "\n)"; + } + String first = sources.get(0); + String nested = buildNestedUnionTransform(unionType, sources.drop(1), privateVar); + return "(" + unionType + "\n " + first + "\n " + nested + "\n $" + privateVar + "\n)"; + } + + @Override + public Env transformIntersect(Env env, RelRN.Intersect intersect) { + Env currentEnv = env; + Seq sourcePatterns = Seq.empty(); + for (RelRN source : intersect.sources()) { + Env sourceEnv = transform(currentEnv, source); + sourcePatterns = sourcePatterns.appended(sourceEnv.current()); + currentEnv = sourceEnv; + } + String privateVar = currentEnv.bindings().get("intersect_private"); + if (privateVar == null) { + privateVar = "private"; + } + String intersectType = intersect.all() ? "IntersectAll" : "Intersect"; + String pattern; + if (sourcePatterns.size() == 2) { + pattern = "(" + intersectType + "\n " + sourcePatterns.get(0) + "\n " + sourcePatterns.get(1) + "\n $" + privateVar + "\n)"; + } else { + String nestedPrivate = currentEnv.bindings().get("inner_intersect_private"); + if (nestedPrivate == null) { + nestedPrivate = privateVar; + } + String nested = buildNestedIntersectTransform(intersectType, sourcePatterns.drop(1), nestedPrivate); + pattern = "(" + intersectType + "\n " + sourcePatterns.get(0) + "\n " + nested + "\n $" + privateVar + "\n)"; + } + return currentEnv.setPattern(pattern).focus(pattern); + } + + + private String buildNestedIntersectTransform(String intersectType, Seq sources, String privateVar) { + if (sources.size() == 2) { + return "(" + intersectType + "\n " + sources.get(0) + "\n " + sources.get(1) + "\n $" + privateVar + "\n)"; + } + String first = sources.get(0); + String nested = buildNestedIntersectTransform(intersectType, sources.drop(1), privateVar); + return "(" + intersectType + "\n " + first + "\n " + nested + "\n $" + privateVar + "\n)"; + } + + @Override + public Env transformAggregate(Env env, RelRN.Aggregate aggregate) { + Env sourceEnv = transform(env, aggregate.source()); + String sourcePattern = sourceEnv.current(); + Env aggsEnv = transformAggCalls(sourceEnv, aggregate.aggCalls()); + String aggsPattern = aggsEnv.current(); + Env groupingEnv = transformGroupSet(aggsEnv, aggregate.groupSet()); + String groupingPattern = groupingEnv.current(); + String privateVar = groupingEnv.bindings().getOrDefault("aggregate_private", "private"); + String aggregateType = determineAggregateType(aggregate); + String pattern = "(" + aggregateType + "\n " + sourcePattern + "\n " + aggsPattern + "\n $" + privateVar + "\n)"; + return groupingEnv.setPattern(pattern).focus(pattern); + } + + private Env transformAggCalls(Env env, Seq aggCalls) { + Env currentEnv = env; + Seq aggPatterns = Seq.empty(); + for (RelRN.AggCall aggCall : aggCalls) { + String aggVar = currentEnv.bindings().getOrDefault(aggCall.name(), "agg"); + aggPatterns = aggPatterns.appended("$" + aggVar); + currentEnv = currentEnv.focus("$" + aggVar); + } + String pattern; + if (aggCalls.size() == 1) { + String aggVar = currentEnv.bindings().getOrDefault("aggregations", "aggregations"); + pattern = "$" + aggVar; + } else { + pattern = "[" + aggPatterns.joinToString(" ") + "]"; + } + return currentEnv.setPattern(pattern).focus(pattern); + } + + private Env transformGroupSet(Env env, Seq groupSet) { + Env currentEnv = env; + Seq groupPatterns = Seq.empty(); + for (RexRN groupCol : groupSet) { + Env groupEnv = transform(currentEnv, groupCol); + groupPatterns = groupPatterns.appended(groupEnv.current()); + currentEnv = groupEnv; + } + String pattern = "[" + groupPatterns.joinToString(" ") + "]"; + return currentEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformEmpty(Env env, RelRN.Empty empty) { + String pattern = "(Values)"; + return env.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformField(Env env, RexRN.Field field) { + String varName = env.bindings().get("field_" + field.ordinal()); + if (varName == null) { + varName = "field"; + } + String pattern = "$" + varName; + return env.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformPred(Env env, RexRN.Pred pred) { + String varName = env.bindings().get(pred.operator().getName()); + if (varName == null) { + varName = "cond"; + } + String pattern = "$" + varName; + return env.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformProj(Env env, RexRN.Proj proj) { + String varName = env.bindings().get(proj.operator().getName()); + if (varName == null) { + varName = "proj"; + } + String pattern = "$" + varName; + return env.setPattern(pattern).focus(pattern); + } + + public Env transformGroupBy(Env env, RexRN.GroupBy groupBy) { + String varName = env.bindings().get(groupBy.operator().getName()); + if (varName == null) { + varName = "groupBy"; + } + String pattern = "$" + varName; + return env.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformAnd(Env env, RexRN.And and) { + Env currentEnv = env; + Seq operandPatterns = Seq.empty(); + + for (RexRN operand : and.sources()) { + Env operandEnv = transform(currentEnv, operand); + operandPatterns = operandPatterns.appended(operandEnv.current()); + currentEnv = operandEnv; + } + + String pattern = "(ConcatFilters " + operandPatterns.joinToString(" ") + ")"; + return currentEnv.setPattern(pattern).focus(pattern); + } + + @Override + public Env transformTrue(Env env, RexRN literal) { + String varName = env.bindings().getOrDefault("true_" + System.identityHashCode(literal), "true"); + return env.setPattern("$" + varName).focus("$" + varName); + } + + @Override + public Env transformFalse(Env env, RexRN literal) { + return env.setPattern("(False)").focus("(False)"); + } + + @Override + public Env transformCustom(Env env, RelRN custom) { + if (custom instanceof org.qed.RRuleInstances.JoinCommute.ProjectionRelRN projection) { + return transform(env, projection.source()); + } + return unimplementedTransform(env, custom); + } + + @Override + public Env transformCustom(Env env, RexRN custom) { + if (custom instanceof RexRN.GroupBy groupBy) { + return transformGroupBy(env, groupBy); + } + return unimplementedTransform(env, custom); + } + + @Override + public String translate(String name, Env onMatch, Env transform) { + StringBuilder sb = new StringBuilder(); + sb.append("[").append(name).append(", Normalize]\n"); + sb.append(onMatch.pattern()).append("\n"); + sb.append("=>\n"); + sb.append(transform.pattern()).append("\n"); + return sb.toString(); + } + + private String getJoinType(org.apache.calcite.rel.core.JoinRelType joinType) { + return switch (joinType) { + case INNER -> "InnerJoin"; + case LEFT -> "LeftJoin"; + case RIGHT -> "RightJoin"; + case FULL -> "FullJoin"; + case SEMI -> "SemiJoin"; + case ANTI -> "AntiJoin"; + default -> "InnerJoin"; + }; + } + + public record Env( + AtomicInteger varId, + String pattern, + ImmutableMap bindings, + String currentVar, + String rulename + ) { + public static Env empty(String rulename) { + return new Env(new AtomicInteger(), "", ImmutableMap.empty(), "", rulename); + } + public Env focus(String target) { + return new Env(varId, pattern, bindings, target, rulename); + } + public Env setPattern(String newPattern) { + return new Env(varId, newPattern, bindings, currentVar, rulename); + } + public Env addBinding(String key, String value) { + return new Env(varId, pattern, bindings.putted(key, value), currentVar, rulename); + } + public String generateVar(String prefix) { + return prefix + "_" + varId.getAndIncrement(); + } + public String current() { + return currentVar; + } + public String pattern() { + return pattern; + } + public ImmutableMap bindings() { + return bindings; + } + public String rulename() { + return rulename; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/qed/Backends/Cockroach/CockroachTester.java b/src/main/java/org/qed/Backends/Cockroach/CockroachTester.java new file mode 100644 index 0000000..567eee6 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/CockroachTester.java @@ -0,0 +1,177 @@ +package org.qed.Backends.Cockroach; + +import kala.tuple.Tuple; +import kala.collection.Seq; +import org.qed.*; +import org.apache.calcite.rel.rules.*; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.plan.RelOptRule; +import org.apache.calcite.plan.hep.HepPlanner; +import org.apache.calcite.plan.hep.HepProgramBuilder; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CockroachTester { + public static String genPath = "src/main/java/org/qed/Backends/Cockroach/Generated"; + public static String rulePath = "rules"; + + public static HepPlanner loadRules(java.util.List rules) { + System.out.printf("Loading Rules: %s\n", + rules.stream() + .map(rule -> rule.getClass().getSimpleName()) + .collect(java.util.stream.Collectors.joining(", "))); + + var builder = new HepProgramBuilder(); + for (var rule : rules) { + builder.addRuleInstance(rule); + } + return new HepPlanner(builder.build()); + } + + public static HepPlanner loadRules(RelOptRule... rules) { + return loadRules(java.util.Arrays.asList(rules)); + } + + public static HepPlanner loadRule(RelOptRule rule) { + System.out.printf("Loading Rule: %s\n", rule.getClass().getSimpleName()); + var builder = new HepProgramBuilder().addRuleInstance(rule); + return new HepPlanner(builder.build()); + } + + public static HepPlanner loadRule(RelOptRule rule, int matchLimit) { + System.out.printf("Loading Rule: %s (match limit: %d)\n", rule.getClass().getSimpleName(), matchLimit); + var builder = new HepProgramBuilder() + .addMatchLimit(matchLimit) + .addRuleInstance(rule); + return new HepPlanner(builder.build()); + } + + public static Seq ruleList() { + java.io.File ruleDir = new java.io.File("src/main/java/org/qed/RRuleInstances"); + java.io.File[] files = ruleDir.listFiles((dir, name) -> name.endsWith(".java")); + + java.util.List rules = new java.util.ArrayList<>(); + + if (files != null) { + for (java.io.File file : files) { + String className = file.getName().replace(".java", ""); + if (className.contains("Distinct") || className.contains("Extract") || className.contains("Pull") || className.contains("False") || className.contains("Prune") || className.contains("Minus") || className.contains("AggregateMerge")) { + continue; + } + + try { + Class clazz = Class.forName("org.qed.RRuleInstances." + className); + RRule rule = (RRule) clazz.getConstructor().newInstance(); + rules.add(rule); + } catch (Exception e) { + throw new RuntimeException("Failed to load rule: " + className, e); + } + } + } + + return Seq.from(rules); + + // var families = Seq.from(reflections.getSubTypesOf(RRule.RRuleFamily.class)) + // .filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) + // .mapUnchecked(clazz -> { + // Constructor constructor = clazz.getDeclaredConstructor(); + // constructor.setAccessible(true); + // return constructor.newInstance(); + // }) + // .map(r -> (RRule.RRuleFamily) r); + + // return individuals.appendedAll(families.flatMap(RRule.RRuleFamily::family)); + } + + public static void verify() { + ruleList().forEachUnchecked(rule -> rule.dump(rulePath + "/" + rule.name() + ".json")); + } + + public static void generate() { + var tester = new CockroachTester(); + ruleList().forEach(r -> tester.serialize(r, genPath)); + } + + public static void runAllTests() { + String packagePath = "src/main/java/org/qed/Backends/Cockroach/Tests"; + java.io.File testDir = new java.io.File(packagePath); + java.io.File[] testFiles = testDir.listFiles((dir, name) -> name.endsWith("Test.java")); + if (testFiles != null) { + for (java.io.File testFile : testFiles) { + String className = "org.qed.Backends.Calcite.Tests." + testFile.getName().replace(".java", ""); + try { + Class testClass = Class.forName(className); + testClass.getMethod("runTest").invoke(null); + } catch (Exception e) { + throw new RuntimeException("Failed to run test: " + className, e); + } + } + } + } + + public static void main(String[] args) throws IOException { + // var rule = new org.qed.RRuleInstances.AggregateExtractProject(); + // System.out.println(rule.explain()); + // Files.createDirectories(Path.of(rulePath)); + // new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(Path.of(rulePath, rule.name() + "-" + rule.info() + ".json").toFile(), rule.toJson()); + // var rules = new RRuleInstance.JoinAssociate(); + // Files.createDirectories(Path.of(rulePath)); + // for (var rule : rules.family()) { + // new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(Path.of(rulePath, rule.name() + "-" + rule.info() + ".json").toFile(), rule.toJson()); + // } + generate(); + runAllTests(); + } + + public void serialize(RRule rule, String path) { + var generator = new CockroachGenerator(); + var code_gen = generator.generate(rule); + try { + Files.write(Path.of(path, rule.name() + ".opt"), code_gen.getBytes()); + } catch (IOException ioe) { + System.err.println(ioe.getMessage()); + } + } + + public void test(RelOptRule rule, Seq tests) { + System.out.println("Testing rule " + rule.getClass().getSimpleName()); + var runner = loadRule(rule); + var exams = tests.mapUnchecked(t -> Tuple.of(t, JSONDeserializer.load(new File(t)))); + for (var entry : exams) { + if (entry.getValue().size() != 2) { + System.err.println(entry.getKey() + " does not have exactly two nodes, and thus is not a valid test"); + continue; + } + verify(runner, entry.getValue().get(0), entry.getValue().get(1)); + } + } + + public void verify(HepPlanner runner, RelNode source, RelNode target) { + runner.setRoot(source); + var answer = runner.findBestExp(); + + String answerExplain = answer.explain(); + String targetExplain = target.explain(); + + if(answerExplain.equals(targetExplain)) { + if(answerExplain.equals(source.explain())) + { + System.out.println("trivial"); + System.out.println("> Given source RelNode:\n" + source.explain()); + System.out.println("> Actual rewritten RelNode:\n" + answerExplain); + System.out.println("> Expected rewritten RelNode:\n" + targetExplain); + } + else + { + System.out.println("succeeded"); + } + return; + } + System.out.println("failed"); + System.out.println("> Given source RelNode:\n" + source.explain()); + System.out.println("> Actual rewritten RelNode:\n" + answerExplain); + System.out.println("> Expected rewritten RelNode:\n" + targetExplain); + } +} \ No newline at end of file diff --git a/src/main/java/org/qed/Backends/Cockroach/CockroachTests b/src/main/java/org/qed/Backends/Cockroach/CockroachTests new file mode 100644 index 0000000..1ca9357 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/CockroachTests @@ -0,0 +1,318 @@ +exec-ddl +CREATE TABLE a (k INT PRIMARY KEY, i INT, f FLOAT, s STRING, j JSON) +---- + +exec-ddl +CREATE TABLE t.b (x INT PRIMARY KEY, y INT) +---- + +exec-ddl +CREATE TABLE f (k INT PRIMARY KEY, i INT, f FLOAT, s STRING NOT NULL, j JSON) +---- + +exec-ddl +CREATE TABLE xy (x INT PRIMARY KEY, y INT) +---- + +exec-ddl +CREATE TABLE uv (u INT PRIMARY KEY, v INT) +---- + +exec-ddl +CREATE TABLE c (a BOOL, b BOOL, c BOOL, d BOOL, e BOOL) +---- + +exec-ddl +CREATE TABLE d (k INT PRIMARY KEY, a INT NOT NULL, b INT, c INT, d FLOAT) +---- + +exec-ddl +CREATE TABLE t (a INT PRIMARY KEY, b INT, c INT) +---- + +exec-ddl +CREATE TABLE e +( + k INT PRIMARY KEY, + i INT, + t TIMESTAMP, + tz TIMESTAMPTZ, + d DATE +) +---- + +exec-ddl +CREATE TABLE rls (x INT PRIMARY KEY, y INT, alice_has_access BOOL); +---- + +exec-ddl +CREATE INDEX ON rls(y); +---- + +exec-ddl +ALTER TABLE rls ENABLE ROW LEVEL SECURITY; +---- + +exec-ddl +CREATE POLICY select_policy_alice +ON rls +FOR SELECT +TO alice +USING (alice_has_access); +---- + +exec-ddl +CREATE ROLE alice; +---- + +# -------------------------------------------------- +# FilterMerge +# -------------------------------------------------- +norm expect=FilterMerge +SELECT * FROM (SELECT * FROM a WHERE k=3) WHERE s='foo' +---- +select + ├── columns: k:1!null i:2 f:3 s:4!null j:5 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(1-5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + ├── k:1 = 3 [outer=(1), constraints=(/1: [/3 - /3]; tight), fd=()-->(1)] + └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] + +norm expect=FilterMerge +SELECT * FROM (SELECT * FROM a WHERE k=3) WHERE s='foo' +---- +select + ├── columns: k:1!null i:2 f:3 s:4!null j:5 + ├── cardinality: [0 - 1] + ├── key: () + ├── fd: ()-->(1-5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + ├── k:1 = 3 [outer=(1), constraints=(/1: [/3 - /3]; tight), fd=()-->(1)] + └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] + +norm expect=FilterMerge +SELECT * FROM (SELECT * FROM a WHERE i=1) WHERE False +---- +values + ├── columns: k:1!null i:2!null f:3!null s:4!null j:5!null + ├── cardinality: [0 - 0] + ├── key: () + └── fd: ()-->(1-5) + +norm expect=FilterMerge +SELECT * FROM (SELECT * FROM a WHERE i<5) WHERE s='foo' +---- +select + ├── columns: k:1!null i:2!null f:3 s:4!null j:5 + ├── key: (1) + ├── fd: ()-->(4), (1)-->(2,3,5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + ├── i:2 < 5 [outer=(2), constraints=(/2: (/NULL - /4]; tight)] + └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] + +norm expect=FilterMerge +SELECT * FROM (SELECT * FROM a WHERE i>1 AND i<10) WHERE s='foo' OR k=5 +---- +select + ├── columns: k:1!null i:2!null f:3 s:4 j:5 + ├── key: (1) + ├── fd: (1)-->(2-5) + ├── scan a + │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ ├── key: (1) + │ └── fd: (1)-->(2-5) + └── filters + ├── (i:2 > 1) AND (i:2 < 10) [outer=(2), constraints=(/2: [/2 - /9]; tight)] + └── (s:4 = 'foo') OR (k:1 = 5) [outer=(1,4)] + +norm expect=FilterIntoJoin +SELECT * FROM a INNER JOIN b ON a.k=b.x WHERE a.s='foo' +---- +inner-join (hash) + ├── columns: k:1!null i:2 f:3 s:4!null j:5 x:8!null y:9 + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + ├── key: (8) + ├── fd: ()-->(4), (1)-->(2,3,5), (8)-->(9), (1)==(8), (8)==(1) + ├── select + │ ├── columns: k:1!null i:2 f:3 s:4!null j:5 + │ ├── key: (1) + │ ├── fd: ()-->(4), (1)-->(2,3,5) + │ ├── scan a + │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2-5) + │ └── filters + │ └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] + ├── scan b + │ ├── columns: x:8!null y:9 + │ ├── key: (8) + │ └── fd: (8)-->(9) + └── filters + └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] + +norm expect=FilterProjectTranspose disable=ProjectFilterTranspose +SELECT * FROM (SELECT i, i+1 AS r, f FROM a) a WHERE f=10.0 +---- +project + ├── columns: i:2 r:8 f:3!null + ├── immutable + ├── fd: ()-->(3), (2)-->(8) + ├── select + │ ├── columns: i:2 f:3!null + │ ├── fd: ()-->(3) + │ ├── scan a + │ │ └── columns: i:2 f:3 + │ └── filters + │ └── f:3 = 10.0 [outer=(3), constraints=(/3: [/10.0 - /10.0]; tight), fd=()-->(3)] + └── projections + └── i:2 + 1 [as=r:8, outer=(2), immutable] + +norm expect=SemiJoinFilterTranspose disable=ProjectFilterTranspose +SELECT * FROM xy WHERE EXISTS (SELECT 1 FROM uv WHERE uv.u = xy.x) AND xy.y > 10 +---- +semi-join (hash) + ├── columns: x:1!null y:2!null + ├── key: (1) + ├── fd: (1)-->(2) + ├── select + │ ├── columns: x:1!null y:2!null + │ ├── key: (1) + │ ├── fd: (1)-->(2) + │ ├── scan xy + │ │ ├── columns: x:1!null y:2 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2) + │ └── filters + │ └── y:2 > 10 [outer=(2), constraints=(/2: [/11 - ]; tight)] + ├── scan uv + │ ├── columns: u:5!null + │ └── key: (5) + └── filters + └── u:5 = x:1 [outer=(1,5), constraints=(/1: (/NULL - ]; /5: (/NULL - ]), fd=(1)==(5), (5)==(1)] + +norm expect=ProjectFilterTranspose disable=FilterProjectTranspose +SELECT * FROM (SELECT i FROM a WHERE i=100) a +---- +select + ├── columns: i:2!null + ├── fd: ()-->(2) + ├── scan a + │ └── columns: i:2 + └── filters + └── i:2 = 100 [outer=(2), constraints=(/2: [/100 - /100]; tight), fd=()-->(2)] + +norm expect=FilterReduceTrue +SELECT * FROM a WHERE True +---- +scan a + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── key: (1) + └── fd: (1)-->(2-5) + +exec-ddl +CREATE INDEX partial_idx ON a (s) WHERE true +---- + +norm expect=FilterReduceTrue +SELECT * FROM a +---- +scan a + ├── columns: k:1!null i:2 f:3 s:4 j:5 + ├── partial index predicates + │ └── partial_idx: filters (true) + ├── key: (1) + └── fd: (1)-->(2-5) + +exec-ddl +DROP INDEX partial_idx +---- + +norm expect=UnionMerge disable=ConvertUnionToDistinctUnionAll +SELECT a, b, c FROM + (SELECT a, b, c FROM t WHERE a < 0) +UNION + (SELECT a, b, c FROM t WHERE b > 10 AND b < 100) +UNION + (SELECT a, b, c FROM t WHERE b > 1000) +---- +union + ├── columns: a:19 b:20 c:21 + ├── left columns: a:11 b:12 c:13 + ├── right columns: t.a:14 t.b:15 t.c:16 + ├── key: (19-21) + ├── select + │ ├── columns: t.a:1!null t.b:2 t.c:3 + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ ├── scan t + │ │ ├── columns: t.a:1!null t.b:2 t.c:3 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2,3) + │ └── filters + │ └── t.a:1 < 0 [outer=(1), constraints=(/1: (/NULL - /-1]; tight)] + └── union + ├── columns: a:11 b:12 c:13 + ├── left columns: t.a:1 t.b:2 t.c:3 + ├── right columns: t.a:6 t.b:7 t.c:8 + ├── key: (11-13) + ├── select + │ ├── columns: t.a:6!null t.b:7!null t.c:8 + │ ├── key: (6) + │ ├── fd: (6)-->(7,8) + │ ├── scan t + │ │ ├── columns: t.a:6!null t.b:7 t.c:8 + │ │ ├── key: (6) + │ │ └── fd: (6)-->(7,8) + │ └── filters + │ └── (t.b:7 > 10) AND (t.b:7 < 100) [outer=(7), constraints=(/7: [/11 - /99]; tight)] + └── select + ├── columns: t.a:14!null t.b:15!null t.c:16 + ├── key: (14) + ├── fd: (14)-->(15,16) + ├── scan t + │ ├── columns: t.a:14!null t.b:15 t.c:16 + │ ├── key: (14) + │ └── fd: (14)-->(15,16) + └── filters + └── t.b:15 > 1000 [outer=(15), constraints=(/15: [/1001 - ]; tight)] + + +norm expect=JoinPushTransitivePredicates disable=FilterIntoJoin +SELECT * FROM a INNER JOIN b ON a.k = b.x WHERE a.s='foo' +---- +inner-join (hash) + ├── columns: k:1!null i:2 f:3 s:4!null j:5 x:8!null y:9 + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + ├── key: (8) + ├── fd: ()-->(4), (1)-->(2,3,5), (8)-->(9), (1)==(8), (8)==(1) + ├── select + │ ├── columns: k:1!null i:2 f:3 s:4!null j:5 + │ ├── key: (1) + │ ├── fd: ()-->(4), (1)-->(2,3,5) + │ ├── scan a + │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 + │ │ ├── key: (1) + │ │ └── fd: (1)-->(2-5) + │ └── filters + │ └── s:4 = 'foo' [outer=(4), constraints=(/4: [/'foo' - /'foo']; tight), fd=()-->(4)] + ├── scan b + │ ├── columns: x:8!null y:9 + │ ├── key: (8) + │ └── fd: (8)-->(9) + └── filters + └── k:1 = x:8 [outer=(1,8), constraints=(/1: (/NULL - ]; /8: (/NULL - ]), fd=(1)==(8), (8)==(1)] + diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/AggregateFilterTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/AggregateFilterTranspose.opt new file mode 100644 index 0000000..92865e2 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/AggregateFilterTranspose.opt @@ -0,0 +1,18 @@ +[AggregateFilterTranspose, Normalize] +(GroupBy + (Select + $input_0:* + $cond_1:* +) + $aggregations_3:* + $private_5:* +) +=> +(Select + (GroupBy + $input_0 + $aggregations_3 + $private_5 +) + $cond_1 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterAggregateTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterAggregateTranspose.opt new file mode 100644 index 0000000..085da99 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterAggregateTranspose.opt @@ -0,0 +1,18 @@ +[FilterAggregateTranspose, Normalize] +(Select + (GroupBy + $input_0:* + $aggregations_2:* + $private_4:* +) + $cond_5:* +) +=> +(GroupBy + (Select + $input_0 + $cond_5 +) + $aggregations_2 + $private_4 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterIntoJoin.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterIntoJoin.opt new file mode 100644 index 0000000..7891e73 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterIntoJoin.opt @@ -0,0 +1,17 @@ +[FilterIntoJoin, Normalize] +(Select + (InnerJoin + $input_0:* + $input_1:* + $cond_2:* + $private_3:* +) + $cond_4:* +) +=> +(InnerJoin + $input_0 + $input_1 + (ConcatFilters $cond_2 $cond_4) + $private_3 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterMerge.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterMerge.opt new file mode 100644 index 0000000..fd1e5e7 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterMerge.opt @@ -0,0 +1,13 @@ +[FilterMerge, Normalize] +(Select + (Select + $input_0:* + $cond_1:* +) + $cond_2:* +) +=> +(Select + $input_0 + (ConcatFilters $cond_1 $cond_2) +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterProjectTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterProjectTranspose.opt new file mode 100644 index 0000000..2539436 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterProjectTranspose.opt @@ -0,0 +1,18 @@ +[FilterProjectTranspose, Normalize] +(Select + (Project + $input_0:* + $proj_1:* + $passthrough_2:* +) + $cond_3:* +) +=> +(Project + (Select + $input_0 + $cond_3 +) + $proj_1 + $passthrough_2 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterReduceTrue.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterReduceTrue.opt new file mode 100644 index 0000000..fe74434 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterReduceTrue.opt @@ -0,0 +1,7 @@ +[FilterReduceTrue, Normalize] +(Select + $input_0:* + [] +) +=> +$input_0 diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/FilterSetOpTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterSetOpTranspose.opt new file mode 100644 index 0000000..b9b1992 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/FilterSetOpTranspose.opt @@ -0,0 +1,21 @@ +[FilterSetOpTranspose, Normalize] +(Select + (Union + $input_0:* + $input_1:* + $private_2:* +) + $cond_3:* +) +=> +(Union + (Select + $input_0 + $cond_3 +) + (Select + $input_1 + $cond_3 +) + $private_2 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/IntersectMerge.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/IntersectMerge.opt new file mode 100644 index 0000000..1e0e32d --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/IntersectMerge.opt @@ -0,0 +1,20 @@ +[IntersectMerge, Normalize] +(Intersect + (Intersect + $input_0:* + $input_1:* + $private_2:* +) + $input_3:* + $private_4:* +) +=> +(Intersect + $input_0 + (Intersect + $input_1 + $input_3 + $private_2 +) + $private_4 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/JoinAddRedundantSemiJoin.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinAddRedundantSemiJoin.opt new file mode 100644 index 0000000..e1a075a --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinAddRedundantSemiJoin.opt @@ -0,0 +1,19 @@ +[JoinAddRedundantSemiJoin, Normalize] +(InnerJoin + $input_0:* + $input_1:* + $cond_2:* + $private_3:* +) +=> +(InnerJoin + (SemiJoin + $input_0 + $input_1 + $cond_2 + $private_3 +) + $input_1 + $cond_2 + $private_3 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/JoinCommute.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinCommute.opt new file mode 100644 index 0000000..fb7a3be --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinCommute.opt @@ -0,0 +1,14 @@ +[JoinCommute, Normalize] +(InnerJoin + $input_0:* + $input_1:* + $cond_2:* + $private_3:* +) +=> +(InnerJoin + $input_1 + $input_0 + $cond_2 + $private_3 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/JoinPushTransitivePredicates.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinPushTransitivePredicates.opt new file mode 100644 index 0000000..64df07e --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/JoinPushTransitivePredicates.opt @@ -0,0 +1,17 @@ +[JoinPushTransitivePredicates, Normalize] +(Select + (InnerJoin + $input_0:* + $input_1:* + $cond_2:* + $private_3:* +) + $cond_4:* +) +=> +(InnerJoin + $input_0 + $input_1 + (ConcatFilters $cond_2 $cond_4) + $private_3 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectFilterTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectFilterTranspose.opt new file mode 100644 index 0000000..2570cdc --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectFilterTranspose.opt @@ -0,0 +1,18 @@ +[ProjectFilterTranspose, Normalize] +(Project + (Select + $input_0:* + $cond_1:* +) + $proj_2:* + $passthrough_3:* +) +=> +(Select + (Project + $input_0 + $proj_2 + $passthrough_3 +) + $cond_1 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectMerge.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectMerge.opt new file mode 100644 index 0000000..cc0543b --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/ProjectMerge.opt @@ -0,0 +1,23 @@ +[ProjectMerge, Normalize] +(Project + $input:(Project + $input_1:* + $proj_2:* + $innerPassthrough_3:*) + $proj_0:* & + (CanMergeProjections $proj_0 $proj_2) + $passthrough_4:* +) +=> +(Project + $input_1 + (MergeProjections + $proj_0 + $proj_2 + $passthrough_4 + ) + (DifferenceCols + $innerPassthrough_3 + (ProjectionCols $proj_2) + ) +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/SemiJoinFilterTranspose.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/SemiJoinFilterTranspose.opt new file mode 100644 index 0000000..9b8dec3 --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/SemiJoinFilterTranspose.opt @@ -0,0 +1,20 @@ +[SemiJoinFilterTranspose, Normalize] +(Select + (SemiJoin + $input_0:* + $input_1:* + $cond_2:* + $private_3:* +) + $cond_4:* +) +=> +(SemiJoin + (Select + $input_0 + $cond_4 +) + $input_1 + $cond_2 + $private_3 +) diff --git a/src/main/java/org/qed/Backends/Cockroach/Generated/UnionMerge.opt b/src/main/java/org/qed/Backends/Cockroach/Generated/UnionMerge.opt new file mode 100644 index 0000000..5e1e67a --- /dev/null +++ b/src/main/java/org/qed/Backends/Cockroach/Generated/UnionMerge.opt @@ -0,0 +1,20 @@ +[UnionMerge, Normalize] +(Union + (Union + $input_0:* + $input_1:* + $private_2:* +) + $input_3:* + $private_4:* +) +=> +(Union + $input_0 + (Union + $input_1 + $input_3 + $private_2 +) + $private_4 +) diff --git a/src/main/java/org/qed/Generated/mysql/FilterMerge1.sql b/src/main/java/org/qed/Backends/MySQL/Generated/FilterMerge1.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/FilterMerge1.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/FilterMerge1.sql diff --git a/src/main/java/org/qed/Generated/mysql/FilterMerge2.sql b/src/main/java/org/qed/Backends/MySQL/Generated/FilterMerge2.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/FilterMerge2.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/FilterMerge2.sql diff --git a/src/main/java/org/qed/Generated/mysql/JoinCommute1.sql b/src/main/java/org/qed/Backends/MySQL/Generated/JoinCommute1.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/JoinCommute1.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/JoinCommute1.sql diff --git a/src/main/java/org/qed/Generated/mysql/JoinCommute2.sql b/src/main/java/org/qed/Backends/MySQL/Generated/JoinCommute2.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/JoinCommute2.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/JoinCommute2.sql diff --git a/src/main/java/org/qed/Generated/mysql/ProjectMerge1.sql b/src/main/java/org/qed/Backends/MySQL/Generated/ProjectMerge1.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/ProjectMerge1.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/ProjectMerge1.sql diff --git a/src/main/java/org/qed/Generated/mysql/ProjectMerge2.sql b/src/main/java/org/qed/Backends/MySQL/Generated/ProjectMerge2.sql similarity index 100% rename from src/main/java/org/qed/Generated/mysql/ProjectMerge2.sql rename to src/main/java/org/qed/Backends/MySQL/Generated/ProjectMerge2.sql diff --git a/src/main/java/org/qed/Generated/MySQLGenerator.java b/src/main/java/org/qed/Backends/MySQL/MySQLGenerator.java similarity index 98% rename from src/main/java/org/qed/Generated/MySQLGenerator.java rename to src/main/java/org/qed/Backends/MySQL/MySQLGenerator.java index c8a6e48..de800f4 100644 --- a/src/main/java/org/qed/Generated/MySQLGenerator.java +++ b/src/main/java/org/qed/Backends/MySQL/MySQLGenerator.java @@ -1,8 +1,8 @@ -package org.qed.Generated; +package org.qed.Backends.MySQL; -import org.qed.Generated.RRuleInstances.JoinCommute; import org.qed.RelRN; import org.qed.RexRN; +import org.qed.RRuleInstances.JoinCommute; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/org/qed/Generated/Test-MySQL/FilterMerge1Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/FilterMerge1Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/FilterMerge1Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/FilterMerge1Test.sql diff --git a/src/main/java/org/qed/Generated/Test-MySQL/FilterMerge2Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/FilterMerge2Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/FilterMerge2Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/FilterMerge2Test.sql diff --git a/src/main/java/org/qed/Generated/Test-MySQL/JoinCommute1Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/JoinCommute1Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/JoinCommute1Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/JoinCommute1Test.sql diff --git a/src/main/java/org/qed/Generated/Test-MySQL/JoinCommute2Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/JoinCommute2Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/JoinCommute2Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/JoinCommute2Test.sql diff --git a/src/main/java/org/qed/Generated/MySQLTester.java b/src/main/java/org/qed/Backends/MySQL/Tests/MySQLTester.java similarity index 78% rename from src/main/java/org/qed/Generated/MySQLTester.java rename to src/main/java/org/qed/Backends/MySQL/Tests/MySQLTester.java index f5707fa..9b6b62c 100644 --- a/src/main/java/org/qed/Generated/MySQLTester.java +++ b/src/main/java/org/qed/Backends/MySQL/Tests/MySQLTester.java @@ -1,6 +1,8 @@ -package org.qed.Generated; +package org.qed.Backends.MySQL.Tests; import org.qed.*; +import org.qed.Backends.MySQL.MySQLGenerator; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -8,19 +10,19 @@ public class MySQLTester { - public static String genPath = "src/main/java/org/qed/Generated/mysql"; + public static String genPath = "src/main/java/org/qed/Backends/MySQL/Generated"; public static String tableName = "testdb.users"; public static List columnNames = List.of("id", "status"); public static void main(String[] args) { - var filterRule = new org.qed.Generated.RRuleInstances.FilterMerge(); + var filterRule = new org.qed.RRuleInstances.FilterMerge(); new MySQLTester().serializeWithNumericSuffix(filterRule, genPath); - var projectRule = new org.qed.Generated.RRuleInstances.ProjectMerge(); + var projectRule = new org.qed.RRuleInstances.ProjectMerge(); new MySQLTester().serializeWithNumericSuffix(projectRule, genPath); - var joinCommute = new org.qed.Generated.RRuleInstances.JoinCommute(); + var joinCommute = new org.qed.RRuleInstances.JoinCommute(); new MySQLTester().serializeWithNumericSuffix(joinCommute, genPath); } diff --git a/src/main/java/org/qed/Generated/Test-MySQL/ProjectMerge1Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/ProjectMerge1Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/ProjectMerge1Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/ProjectMerge1Test.sql diff --git a/src/main/java/org/qed/Generated/Test-MySQL/ProjectMerge2Test.sql b/src/main/java/org/qed/Backends/MySQL/Tests/ProjectMerge2Test.sql similarity index 100% rename from src/main/java/org/qed/Generated/Test-MySQL/ProjectMerge2Test.sql rename to src/main/java/org/qed/Backends/MySQL/Tests/ProjectMerge2Test.sql diff --git a/src/main/java/org/qed/Generated/script-mysql.py b/src/main/java/org/qed/Backends/MySQL/Tests/script-mysql.py similarity index 82% rename from src/main/java/org/qed/Generated/script-mysql.py rename to src/main/java/org/qed/Backends/MySQL/Tests/script-mysql.py index 14c8c6c..136e5ce 100644 --- a/src/main/java/org/qed/Generated/script-mysql.py +++ b/src/main/java/org/qed/Backends/MySQL/Tests/script-mysql.py @@ -1,16 +1,13 @@ import mysql.connector from pathlib import Path -# Database connection info MYSQL_USER = "root" MYSQL_PASSWORD = "wkaiz" MYSQL_DATABASE = "query_rewrite" -# Paths (relative to script.py) -RULE_DIR = Path("mysql") -TEST_DIR = Path("Test-MySQL") +RULE_DIR = Path("../Generated") +TEST_DIR = Path(".") -# Connect to MySQL conn = mysql.connector.connect( host="localhost", user=MYSQL_USER, @@ -19,9 +16,7 @@ ) cursor = conn.cursor() -# Iterate over all .sql files in rule directory for rule_file in RULE_DIR.glob("*.sql"): - # Match test file (rule_file.stem + "test.sql") test_file = TEST_DIR / f"{rule_file.stem}test.sql" if not test_file.exists(): @@ -30,7 +25,6 @@ print(f"\n=== Running rule {rule_file.name} with test {test_file.name} ===") - # Load and execute rule SQL with rule_file.open("r", encoding="utf-8") as f: sql_commands = f.read() @@ -45,8 +39,6 @@ conn.commit() print(f"{rule_file} executed successfully.") - - # Delete all rules except the last one cursor.execute(""" DELETE FROM rewrite_rules WHERE id < ( @@ -56,18 +48,15 @@ conn.commit() print("Deleted all rules except the last one.") - # Flush rewrite rules cursor.execute("CALL flush_rewrite_rules();") conn.commit() print("Flushed rewrite rules.") - # Show current rules cursor.execute("SELECT * FROM rewrite_rules;") print("Current rules in table:") for row in cursor.fetchall(): print(row) - # Load and run test query with test_file.open("r", encoding="utf-8") as f: test_query = f.read().strip() @@ -81,13 +70,11 @@ print(f"❌ Error running test query {test_file.name}: {e}") continue - # Show warnings (should indicate rewrite) cursor.execute("SHOW WARNINGS;") warnings = cursor.fetchall() print("\nWarnings (should indicate rewrite):") for w in warnings: print(w) -# Cleanup cursor.close() conn.close() diff --git a/src/main/java/org/qed/Generated/proxysql/FilterMerge.sql b/src/main/java/org/qed/Backends/ProxySQL/Generated/FilterMerge.sql similarity index 100% rename from src/main/java/org/qed/Generated/proxysql/FilterMerge.sql rename to src/main/java/org/qed/Backends/ProxySQL/Generated/FilterMerge.sql diff --git a/src/main/java/org/qed/Generated/proxysql/FilterReduceFalse.sql b/src/main/java/org/qed/Backends/ProxySQL/Generated/FilterReduceFalse.sql similarity index 100% rename from src/main/java/org/qed/Generated/proxysql/FilterReduceFalse.sql rename to src/main/java/org/qed/Backends/ProxySQL/Generated/FilterReduceFalse.sql diff --git a/src/main/java/org/qed/Generated/proxysql/FilterReduceTrue.sql b/src/main/java/org/qed/Backends/ProxySQL/Generated/FilterReduceTrue.sql similarity index 100% rename from src/main/java/org/qed/Generated/proxysql/FilterReduceTrue.sql rename to src/main/java/org/qed/Backends/ProxySQL/Generated/FilterReduceTrue.sql diff --git a/src/main/java/org/qed/Generated/proxysql/JoinCommute.sql b/src/main/java/org/qed/Backends/ProxySQL/Generated/JoinCommute.sql similarity index 100% rename from src/main/java/org/qed/Generated/proxysql/JoinCommute.sql rename to src/main/java/org/qed/Backends/ProxySQL/Generated/JoinCommute.sql diff --git a/src/main/java/org/qed/Generated/proxysql/ProjectMerge.sql b/src/main/java/org/qed/Backends/ProxySQL/Generated/ProjectMerge.sql similarity index 100% rename from src/main/java/org/qed/Generated/proxysql/ProjectMerge.sql rename to src/main/java/org/qed/Backends/ProxySQL/Generated/ProjectMerge.sql diff --git a/src/main/java/org/qed/Generated/ProxySQLGenerator.java b/src/main/java/org/qed/Backends/ProxySQL/ProxySQLGenerator.java similarity index 99% rename from src/main/java/org/qed/Generated/ProxySQLGenerator.java rename to src/main/java/org/qed/Backends/ProxySQL/ProxySQLGenerator.java index 846b627..50f6983 100644 --- a/src/main/java/org/qed/Generated/ProxySQLGenerator.java +++ b/src/main/java/org/qed/Backends/ProxySQL/ProxySQLGenerator.java @@ -1,8 +1,8 @@ package org.qed.Generated; -import org.qed.Generated.RRuleInstances.JoinCommute; import org.qed.RelRN; import org.qed.RexRN; +import org.qed.RRuleInstances.JoinCommute; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/org/qed/Generated/Tests-ProxySQL/FilterMergeTest.sql b/src/main/java/org/qed/Backends/ProxySQL/Tests/FilterMergeTest.sql similarity index 100% rename from src/main/java/org/qed/Generated/Tests-ProxySQL/FilterMergeTest.sql rename to src/main/java/org/qed/Backends/ProxySQL/Tests/FilterMergeTest.sql diff --git a/src/main/java/org/qed/Generated/Tests-ProxySQL/FilterReduceFalseTest.sql b/src/main/java/org/qed/Backends/ProxySQL/Tests/FilterReduceFalseTest.sql similarity index 100% rename from src/main/java/org/qed/Generated/Tests-ProxySQL/FilterReduceFalseTest.sql rename to src/main/java/org/qed/Backends/ProxySQL/Tests/FilterReduceFalseTest.sql diff --git a/src/main/java/org/qed/Generated/Tests-ProxySQL/FilterReduceTrueTest.sql b/src/main/java/org/qed/Backends/ProxySQL/Tests/FilterReduceTrueTest.sql similarity index 100% rename from src/main/java/org/qed/Generated/Tests-ProxySQL/FilterReduceTrueTest.sql rename to src/main/java/org/qed/Backends/ProxySQL/Tests/FilterReduceTrueTest.sql diff --git a/src/main/java/org/qed/Generated/Tests-ProxySQL/JoinCommuteTest.sql b/src/main/java/org/qed/Backends/ProxySQL/Tests/JoinCommuteTest.sql similarity index 100% rename from src/main/java/org/qed/Generated/Tests-ProxySQL/JoinCommuteTest.sql rename to src/main/java/org/qed/Backends/ProxySQL/Tests/JoinCommuteTest.sql diff --git a/src/main/java/org/qed/Generated/Tests-ProxySQL/ProjectMergeTest.sql b/src/main/java/org/qed/Backends/ProxySQL/Tests/ProjectMergeTest.sql similarity index 100% rename from src/main/java/org/qed/Generated/Tests-ProxySQL/ProjectMergeTest.sql rename to src/main/java/org/qed/Backends/ProxySQL/Tests/ProjectMergeTest.sql diff --git a/src/main/java/org/qed/Generated/script-proxysql.sh b/src/main/java/org/qed/Backends/ProxySQL/Tests/script-proxysql.sh similarity index 100% rename from src/main/java/org/qed/Generated/script-proxysql.sh rename to src/main/java/org/qed/Backends/ProxySQL/Tests/script-proxysql.sh diff --git a/src/main/java/org/qed/Generated/CalciteUtilities.java b/src/main/java/org/qed/Generated/CalciteUtilities.java deleted file mode 100644 index 22e545c..0000000 --- a/src/main/java/org/qed/Generated/CalciteUtilities.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.qed.Generated; - -import org.apache.calcite.plan.RelOptUtil; -import org.apache.calcite.rel.RelNode; -import org.apache.calcite.rel.core.Project; -import org.apache.calcite.rex.RexNode; -import org.qed.RuleBuilder; - -import java.util.List; - -public record CalciteUtilities() { - public List compose(RelNode base, List inner, List outer) { - var builder = RuleBuilder.create(); - return RelOptUtil.pushPastProject(outer, (Project) builder.push(base).project(inner).build()); - } -} diff --git a/src/main/java/org/qed/Generated/ProxySQLTester.java b/src/main/java/org/qed/Generated/ProxySQLTester.java deleted file mode 100644 index 349857a..0000000 --- a/src/main/java/org/qed/Generated/ProxySQLTester.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.qed.Generated; - -import org.qed.RRule; -import org.qed.Generated.RRuleInstances.FilterMerge; -import org.qed.Generated.RRuleInstances.ProjectMerge; -import org.qed.Generated.RRuleInstances.JoinCommute; -import org.qed.Generated.RRuleInstances.FilterReduceFalse; -import org.qed.Generated.RRuleInstances.FilterReduceTrue; // Import the new rule - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -public class ProxySQLTester { - - public static final String OUTPUT_PATH = "src/main/java/org/qed/Generated/proxysql"; - - private int nextRuleId = 10; - - public static void main(String[] args) { - var tester = new ProxySQLTester(); - - List rulesToGenerate = List.of( - new FilterMerge(), - new ProjectMerge(), - new JoinCommute(), - new FilterReduceFalse(), - new FilterReduceTrue() - ); - - for (RRule rule : rulesToGenerate) { - tester.generateRuleFile(rule); - System.out.println(); - } - } - - public void generateRuleFile(RRule rule) { - int currentRuleId = this.nextRuleId; - this.nextRuleId += 10; - - var generator = new ProxySQLGenerator(); - String ruleSql = generator.translate(currentRuleId, rule.name(), rule.before(), rule.after()); - - try { - Path outputDir = Path.of(OUTPUT_PATH); - Files.createDirectories(outputDir); - - String fileName = rule.name() + ".sql"; - Path filePath = outputDir.resolve(fileName); - Files.writeString(filePath, ruleSql); - - } catch (IOException | UnsupportedOperationException e) { - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/main/java/org/qed/Generated/Tests/AggregateProjectMergeTest.java b/src/main/java/org/qed/Generated/Tests/AggregateProjectMergeTest.java deleted file mode 100644 index 30dc574..0000000 --- a/src/main/java/org/qed/Generated/Tests/AggregateProjectMergeTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.qed.Generated.Tests; - -import kala.collection.Seq; -import kala.tuple.Tuple; -import org.qed.Generated.CalciteTester; -import org.qed.RelType; -import org.qed.RuleBuilder; - -public class AggregateProjectMergeTest { - - public static void runTest() { - var tester = new CalciteTester(); - var builder = RuleBuilder.create(); - - // Create EMP table matching the Apache Calcite test structure - var empTable = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // EMPNO (index 0) - Tuple.of(RelType.fromString("VARCHAR", true), false), // ENAME (index 1) - Tuple.of(RelType.fromString("VARCHAR", true), false), // JOB (index 2) - Tuple.of(RelType.fromString("INTEGER", true), false), // MGR (index 3) - Tuple.of(RelType.fromString("DATE", true), false), // HIREDATE (index 4) - Tuple.of(RelType.fromString("DECIMAL", true), false), // SAL (index 5) - Tuple.of(RelType.fromString("DECIMAL", true), false), // COMM (index 6) - Tuple.of(RelType.fromString("INTEGER", true), false) // DEPTNO (index 7) - )); - builder.addTable(empTable); - - var empScan = builder.scan(empTable.getName()).build(); - - // Build the "before" pattern matching the Apache Calcite test: - // select x, sum(z), y from ( - // select deptno as x, empno as y, sal as z, sal * 2 as zz - // from emp) - // group by x, y - var before = builder - .push(empScan) - // Inner project: select deptno as x, empno as y, sal as z - // This corresponds to: X=[$7], Y=[$0], Z=[$5] - .project( - builder.field(7), // DEPTNO -> X (position 0 in projection) - builder.field(0), // EMPNO -> Y (position 1 in projection) - builder.field(5) // SAL -> Z (position 2 in projection) - // Note: sal * 2 as zz is omitted since it's not used by the aggregate - ) - // Aggregate: group by x, y and sum(z) - // This corresponds to: group=[{0, 1}], EXPR$1=[SUM($2)] - .aggregate( - builder.groupKey(builder.field(0), builder.field(1)), // Group by X, Y - builder.sum(builder.field(2)) // SUM(Z) - ) - // Outer project to reorder columns: X, EXPR$1, Y - // This corresponds to: LogicalProject(X=[$0], EXPR$1=[$2], Y=[$1]) - .project( - builder.field(0), // X - builder.field(2), // EXPR$1 (SUM result) - builder.field(1) // Y - ) - .build(); - - // Build the "after" pattern (optimized): - // The inner project is merged with the aggregate - var after = builder - .push(empScan) - // Direct aggregate on base table: group=[{0, 7}], EXPR$1=[SUM($5)] - // This means: GROUP BY EMPNO (0), DEPTNO (7), SUM(SAL) (5) - .aggregate( - builder.groupKey(builder.field(0), builder.field(7)), // Group by EMPNO, DEPTNO - builder.sum(builder.field(5)) // SUM(SAL) - ) - // Intermediate project to match field names: DEPTNO=[$1], EMPNO=[$0], EXPR$1=[$2] - .project( - builder.field(1), // DEPTNO (was at position 1 in aggregate result) - builder.field(0), // EMPNO (was at position 0 in aggregate result) - builder.field(2) // EXPR$1 (SUM result at position 2) - ) - // Final project to match original output order: X=[$0], EXPR$1=[$2], Y=[$1] - .project( - builder.field(0), // X (DEPTNO) - builder.field(2), // EXPR$1 (SUM result) - builder.field(1) // Y (EMPNO) - ) - .build(); - - var runner = CalciteTester.loadRules(org.qed.Generated.AggregateProjectMerge.Config.DEFAULT.toRule(), org.qed.Generated.ProjectMerge.Config.DEFAULT.toRule()); - tester.verify(runner, before, after); - } - - public static void main(String[] args) { - System.out.println("Running AggregateProjectMerge comprehensive test..."); - runTest(); - } -} \ No newline at end of file diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateExtractProject.java b/src/main/java/org/qed/RRuleInstances/AggregateExtractProject.java similarity index 74% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateExtractProject.java rename to src/main/java/org/qed/RRuleInstances/AggregateExtractProject.java index 72aac88..97037fd 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateExtractProject.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateExtractProject.java @@ -1,15 +1,9 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import org.apache.calcite.rel.RelNode; import org.qed.RelRN; import org.qed.RRule; -import org.qed.RuleBuilder; -import org.qed.RelType; import org.qed.RexRN; -import kala.collection.Seq; -import kala.tuple.Tuple; - public record AggregateExtractProject() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); static final RexRN proj = source.proj("proj", "Project_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateFilterTranspose.java b/src/main/java/org/qed/RRuleInstances/AggregateFilterTranspose.java similarity index 82% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateFilterTranspose.java rename to src/main/java/org/qed/RRuleInstances/AggregateFilterTranspose.java index 8974095..6eaba5d 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateFilterTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateFilterTranspose.java @@ -1,11 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RelType; public record AggregateFilterTranspose() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinJoinRemove.java b/src/main/java/org/qed/RRuleInstances/AggregateJoinJoinRemove.java similarity index 97% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinJoinRemove.java rename to src/main/java/org/qed/RRuleInstances/AggregateJoinJoinRemove.java index 7cac22a..b935c3e 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinJoinRemove.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateJoinJoinRemove.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinRemove.java b/src/main/java/org/qed/RRuleInstances/AggregateJoinRemove.java similarity index 96% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinRemove.java rename to src/main/java/org/qed/RRuleInstances/AggregateJoinRemove.java index 9972737..28688e6 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateJoinRemove.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateJoinRemove.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectConstantToDummyJoin.java b/src/main/java/org/qed/RRuleInstances/AggregateProjectConstantToDummyJoin.java similarity index 55% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectConstantToDummyJoin.java rename to src/main/java/org/qed/RRuleInstances/AggregateProjectConstantToDummyJoin.java index 847ad7d..2b47981 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectConstantToDummyJoin.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateProjectConstantToDummyJoin.java @@ -1,76 +1,48 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.RelNode; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RelRN; -import org.qed.RexRN; import org.qed.RRule; import org.qed.RuleBuilder; import org.qed.RelType; import kala.collection.Seq; import kala.tuple.Tuple; -/** - * AggregateProjectConstantToDummyJoinRule: Replaces constant literals in GROUP BY - * with a dummy table join. - * - * Pattern: - * Aggregate(group=[constant_literal, regular_field]) - * Project(constant_literal, regular_field) - * Scan - * - * => - * - * Aggregate(group=[dummy.constant, regular_field]) - * Project(dummy.constant, regular_field) - * Join(Scan, DummyValues(constant_literal)) - * - * This optimization can help with certain database engines that handle - * joins more efficiently than literal constants in GROUP BY clauses. - */ public record AggregateProjectConstantToDummyJoin() implements RRule { - - // Base table for the pattern + static final RelRN baseTable = new BaseEmployeeTable(); @Override public RelRN before() { - // Aggregate over project with constant literals var projectWithConstants = new ProjectWithConstantLiterals(baseTable); return new AggregateGroupingByConstants(projectWithConstants); } @Override public RelRN after() { - // Optimized: join with dummy table containing constants var dummyTable = new DummyConstantsTable(); var joinWithDummy = new JoinWithDummyTable(baseTable, dummyTable); var projectWithDummyFields = new ProjectWithDummyFields(joinWithDummy); return new AggregateGroupingByDummyFields(projectWithDummyFields); } - /** - * Base employee table - */ public static record BaseEmployeeTable() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // emp_id - Tuple.of(RelType.fromString("DECIMAL", true), false), // salary - Tuple.of(RelType.fromString("INTEGER", true), false) // dept_id + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * Project with constant literals: SELECT emp_id, TRUE as active_flag, '2024' as year_label, salary - */ + public static record ProjectWithConstantLiterals(RelRN input) implements RelRN { @Override public RelNode semantics() { @@ -78,63 +50,50 @@ public RelNode semantics() { builder.push(input.semantics()); builder.project( - builder.field(0), // emp_id - builder.alias(builder.literal(true), "active_flag"), // constant: TRUE - builder.alias(builder.literal("2024"), "year_label"), // constant: '2024' - builder.field(1) // salary + builder.field(0), + builder.alias(builder.literal(true), "active_flag"), + builder.alias(builder.literal("2024"), "year_label"), + builder.field(1) ); return builder.build(); } } - - /** - * Aggregate grouping by constant literals: GROUP BY active_flag, year_label, emp_id - */ + public static record AggregateGroupingByConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Group by the constant fields and emp_id + var groupKey = builder.groupKey( - builder.field(1), // active_flag (constant) - builder.field(2), // year_label (constant) - builder.field(0) // emp_id (regular field) + builder.field(1), + builder.field(2), + builder.field(0) ); - - // Aggregate: AVG(salary) + var avgSalary = builder.avg(builder.field(3)); builder.aggregate(groupKey, avgSalary); return builder.build(); } } - - /** - * Dummy table containing the constant values: VALUES (TRUE, '2024') - */ + public static record DummyConstantsTable() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); - - // Create a values table with the constants - // Using the correct values() method signature + builder.values( - new String[]{"active_flag", "year_label"}, // Column names - true, // TRUE constant value - "2024" // '2024' constant value + new String[]{"active_flag", "year_label"}, + true, + "2024" ); return builder.build(); } } - - /** - * Join base table with dummy constants table - */ + public static record JoinWithDummyTable(RelRN baseTable, RelRN dummyTable) implements RelRN { @Override public RelNode semantics() { @@ -142,52 +101,41 @@ public RelNode semantics() { builder.push(baseTable.semantics()); builder.push(dummyTable.semantics()); - - // Cross join (INNER JOIN with TRUE condition) + builder.join(JoinRelType.INNER, builder.literal(true)); return builder.build(); } } - - /** - * Project using dummy fields instead of constants: SELECT emp_id, dummy.active_flag, dummy.year_label, salary - */ + public static record ProjectWithDummyFields(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // After join: base table fields are 0,1,2 and dummy fields are 3,4 + builder.project( - builder.field(0), // emp_id (from base table) - builder.field(3), // active_flag (from dummy table) - builder.field(4), // year_label (from dummy table) - builder.field(1) // salary (from base table) + builder.field(0), + builder.field(3), + builder.field(4), + builder.field(1) ); return builder.build(); } } - - /** - * Aggregate grouping by dummy fields: GROUP BY dummy.active_flag, dummy.year_label, emp_id - */ public static record AggregateGroupingByDummyFields(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Group by the dummy fields and emp_id + var groupKey = builder.groupKey( - builder.field(1), // active_flag (from dummy) - builder.field(2), // year_label (from dummy) - builder.field(0) // emp_id (regular field) + builder.field(1), + builder.field(2), + builder.field(0) ); - - // Same aggregate: AVG(salary) + var avgSalary = builder.avg(builder.field(3)); builder.aggregate(groupKey, avgSalary); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectMerge.java b/src/main/java/org/qed/RRuleInstances/AggregateProjectMerge.java similarity index 74% rename from src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectMerge.java rename to src/main/java/org/qed/RRuleInstances/AggregateProjectMerge.java index a389cf1..cf3da67 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/AggregateProjectMerge.java +++ b/src/main/java/org/qed/RRuleInstances/AggregateProjectMerge.java @@ -1,15 +1,9 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import org.apache.calcite.rel.RelNode; import org.qed.RelRN; import org.qed.RRule; -import org.qed.RuleBuilder; -import org.qed.RelType; import org.qed.RexRN; -import kala.collection.Seq; -import kala.tuple.Tuple; - public record AggregateProjectMerge() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); static final RexRN proj = source.proj("proj", "Project_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterAggregateTranspose.java b/src/main/java/org/qed/RRuleInstances/FilterAggregateTranspose.java similarity index 82% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterAggregateTranspose.java rename to src/main/java/org/qed/RRuleInstances/FilterAggregateTranspose.java index f498113..aa3ada0 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterAggregateTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/FilterAggregateTranspose.java @@ -1,11 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RelType; public record FilterAggregateTranspose() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterIntoJoin.java b/src/main/java/org/qed/RRuleInstances/FilterIntoJoin.java similarity index 78% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterIntoJoin.java rename to src/main/java/org/qed/RRuleInstances/FilterIntoJoin.java index d16f8ef..8dcbd70 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterIntoJoin.java +++ b/src/main/java/org/qed/RRuleInstances/FilterIntoJoin.java @@ -1,13 +1,9 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterIntoJoin() implements RRule { static final RelRN left = RelRN.scan("Left", "Left_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterMerge.java b/src/main/java/org/qed/RRuleInstances/FilterMerge.java similarity index 68% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterMerge.java rename to src/main/java/org/qed/RRuleInstances/FilterMerge.java index d90aa6d..473d3c1 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterMerge.java +++ b/src/main/java/org/qed/RRuleInstances/FilterMerge.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterMerge() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterProjectTranspose.java b/src/main/java/org/qed/RRuleInstances/FilterProjectTranspose.java similarity index 67% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterProjectTranspose.java rename to src/main/java/org/qed/RRuleInstances/FilterProjectTranspose.java index 4c1b229..e7154b4 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterProjectTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/FilterProjectTranspose.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterProjectTranspose() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterReduceFalse.java b/src/main/java/org/qed/RRuleInstances/FilterReduceFalse.java similarity index 61% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterReduceFalse.java rename to src/main/java/org/qed/RRuleInstances/FilterReduceFalse.java index 8b4dd4b..ccaa73c 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterReduceFalse.java +++ b/src/main/java/org/qed/RRuleInstances/FilterReduceFalse.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterReduceFalse() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterReduceTrue.java b/src/main/java/org/qed/RRuleInstances/FilterReduceTrue.java similarity index 61% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterReduceTrue.java rename to src/main/java/org/qed/RRuleInstances/FilterReduceTrue.java index c3dd472..d67d14e 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterReduceTrue.java +++ b/src/main/java/org/qed/RRuleInstances/FilterReduceTrue.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterReduceTrue() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/FilterSetOpTranspose.java b/src/main/java/org/qed/RRuleInstances/FilterSetOpTranspose.java similarity index 73% rename from src/main/java/org/qed/Generated/RRuleInstances/FilterSetOpTranspose.java rename to src/main/java/org/qed/RRuleInstances/FilterSetOpTranspose.java index 2dcf9e2..4d9ea3d 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/FilterSetOpTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/FilterSetOpTranspose.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record FilterSetOpTranspose() implements RRule { static final RelRN left = RelRN.scan("Left", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/IntersectMerge.java b/src/main/java/org/qed/RRuleInstances/IntersectMerge.java similarity index 95% rename from src/main/java/org/qed/Generated/RRuleInstances/IntersectMerge.java rename to src/main/java/org/qed/RRuleInstances/IntersectMerge.java index 27afe67..a4ea680 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/IntersectMerge.java +++ b/src/main/java/org/qed/RRuleInstances/IntersectMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import kala.collection.Map; import kala.collection.Seq; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinAddRedundantSemiJoin.java b/src/main/java/org/qed/RRuleInstances/JoinAddRedundantSemiJoin.java similarity index 73% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinAddRedundantSemiJoin.java rename to src/main/java/org/qed/RRuleInstances/JoinAddRedundantSemiJoin.java index ec54c50..86c6ca7 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinAddRedundantSemiJoin.java +++ b/src/main/java/org/qed/RRuleInstances/JoinAddRedundantSemiJoin.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; -import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record JoinAddRedundantSemiJoin() implements RRule { static final RelRN left = RelRN.scan("Left", "Left_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinCommute.java b/src/main/java/org/qed/RRuleInstances/JoinCommute.java similarity index 83% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinCommute.java rename to src/main/java/org/qed/RRuleInstances/JoinCommute.java index d1580be..ec54ca5 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinCommute.java +++ b/src/main/java/org/qed/RRuleInstances/JoinCommute.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import kala.collection.Seq; import org.apache.calcite.rel.RelNode; @@ -31,16 +31,14 @@ public RelRN after() { return new ProjectionRelRN(swappedJoin); } - - // implementation for the column reordering projection public static record ProjectionRelRN(RelRN source) implements RelRN { @Override public RelNode semantics() { RuleBuilder builder = RuleBuilder.create(); builder.push(source.semantics()); - RexNode leftField = builder.field(1); // Left columns (now at position 1) - RexNode rightField = builder.field(0); // Right columns (now at position 0) + RexNode leftField = builder.field(1); + RexNode rightField = builder.field(0); builder.project(leftField, rightField); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinConditionPush.java b/src/main/java/org/qed/RRuleInstances/JoinConditionPush.java similarity index 98% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinConditionPush.java rename to src/main/java/org/qed/RRuleInstances/JoinConditionPush.java index 74209c7..061a508 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinConditionPush.java +++ b/src/main/java/org/qed/RRuleInstances/JoinConditionPush.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinExtractFilter.java b/src/main/java/org/qed/RRuleInstances/JoinExtractFilter.java similarity index 77% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinExtractFilter.java rename to src/main/java/org/qed/RRuleInstances/JoinExtractFilter.java index 63db3ec..fc78f17 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinExtractFilter.java +++ b/src/main/java/org/qed/RRuleInstances/JoinExtractFilter.java @@ -1,13 +1,9 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record JoinExtractFilter() implements RRule { static final RelRN left = RelRN.scan("Left", "Left_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinPushTransitivePredicates.java b/src/main/java/org/qed/RRuleInstances/JoinPushTransitivePredicates.java similarity index 94% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinPushTransitivePredicates.java rename to src/main/java/org/qed/RRuleInstances/JoinPushTransitivePredicates.java index 1aaa5d9..aa78ede 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinPushTransitivePredicates.java +++ b/src/main/java/org/qed/RRuleInstances/JoinPushTransitivePredicates.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinReduceFalse.java b/src/main/java/org/qed/RRuleInstances/JoinReduceFalse.java similarity index 93% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinReduceFalse.java rename to src/main/java/org/qed/RRuleInstances/JoinReduceFalse.java index 3d7a6fa..a537196 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinReduceFalse.java +++ b/src/main/java/org/qed/RRuleInstances/JoinReduceFalse.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/JoinReduceTrue.java b/src/main/java/org/qed/RRuleInstances/JoinReduceTrue.java similarity index 93% rename from src/main/java/org/qed/Generated/RRuleInstances/JoinReduceTrue.java rename to src/main/java/org/qed/RRuleInstances/JoinReduceTrue.java index 5c2a674..61b2106 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/JoinReduceTrue.java +++ b/src/main/java/org/qed/RRuleInstances/JoinReduceTrue.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/MinusMerge.java b/src/main/java/org/qed/RRuleInstances/MinusMerge.java similarity index 65% rename from src/main/java/org/qed/Generated/RRuleInstances/MinusMerge.java rename to src/main/java/org/qed/RRuleInstances/MinusMerge.java index a080685..9367c63 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/MinusMerge.java +++ b/src/main/java/org/qed/RRuleInstances/MinusMerge.java @@ -1,13 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; -import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record MinusMerge() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/ProjectAggregateMerge.java b/src/main/java/org/qed/RRuleInstances/ProjectAggregateMerge.java similarity index 67% rename from src/main/java/org/qed/Generated/RRuleInstances/ProjectAggregateMerge.java rename to src/main/java/org/qed/RRuleInstances/ProjectAggregateMerge.java index da37476..67593f5 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/ProjectAggregateMerge.java +++ b/src/main/java/org/qed/RRuleInstances/ProjectAggregateMerge.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.RelNode; import org.qed.RelRN; @@ -8,77 +8,46 @@ import kala.collection.Seq; import kala.tuple.Tuple; -/** - * ProjectAggregateMergeRule: Eliminates unused aggregate calls from projections - * and converts COALESCE(SUM(x), 0) to SUM0(x) for better optimization. - * - * Pattern: - * Project(used_group_fields, used_agg_calls, unused_agg_calls) - * Aggregate(group_fields, used_agg_calls, unused_agg_calls) - * Scan - * - * => - * - * Project(used_group_fields, used_agg_calls) - * Aggregate(group_fields, used_agg_calls) -- unused calls removed - * Scan - * - * This optimization reduces the cost of aggregation by eliminating - * aggregate computations that are not used in the final result. - */ public record ProjectAggregateMerge() implements RRule { - - // Base table for the pattern static final RelRN baseTable = new SalesTable(); @Override public RelRN before() { - // Project that uses only some of the aggregate results var aggregateWithUnusedCalls = new AggregateWithMultipleCalls(baseTable); return new ProjectUsingSubsetOfAggregates(aggregateWithUnusedCalls); } @Override public RelRN after() { - // Optimized: aggregate with only used calls var aggregateOptimized = new AggregateWithUsedCallsOnly(baseTable); return new ProjectOptimized(aggregateOptimized); } - /** - * Sales table with multiple numeric columns for aggregation - */ public static record SalesTable() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // region_id - Tuple.of(RelType.fromString("DECIMAL", true), false), // sales_amount - Tuple.of(RelType.fromString("DECIMAL", true), false), // cost_amount - Tuple.of(RelType.fromString("INTEGER", true), false) // quantity + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("DECIMAL", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * Aggregate with multiple calls: GROUP BY region_id, SUM(sales), AVG(cost), COUNT(quantity), MAX(sales) - * Some of these aggregates will be unused in the projection - */ + public static record AggregateWithMultipleCalls(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Group by region_id + var groupKey = builder.groupKey(builder.field(0)); - - // Multiple aggregate calls + var sumSales = builder.sum(false, "sum_sales", builder.field(1)); // Will be used var avgCost = builder.avg(builder.field(2)); // Will be unused var countQty = builder.count(false, "count_qty", builder.field(3)); // Will be used @@ -88,28 +57,17 @@ public RelNode semantics() { return builder.build(); } } - - /** - * Project that uses only some aggregates: SELECT region_id, sum_sales, count_qty - * (avgCost and maxSales are not projected, so they're unused) - */ + public static record ProjectUsingSubsetOfAggregates(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Project only used fields: - // field(0) = region_id (group key) - // field(1) = sum_sales (used aggregate) - // field(2) = avg_cost (UNUSED - not projected) - // field(3) = count_qty (used aggregate) - // field(4) = max_sales (UNUSED - not projected) + builder.project( - builder.alias(builder.field(0), "region_id"), // Group key - builder.alias(builder.field(1), "total_sales"), // Used: sum_sales - builder.alias(builder.field(3), "total_count") // Used: count_qty - // avg_cost (field 2) and max_sales (field 4) are not projected + builder.alias(builder.field(0), "region_id"), + builder.alias(builder.field(1), "total_sales"), + builder.alias(builder.field(3), "total_count") ); return builder.build(); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/ProjectFilterTranspose.java b/src/main/java/org/qed/RRuleInstances/ProjectFilterTranspose.java similarity index 91% rename from src/main/java/org/qed/Generated/RRuleInstances/ProjectFilterTranspose.java rename to src/main/java/org/qed/RRuleInstances/ProjectFilterTranspose.java index c8d97bc..2a652e6 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/ProjectFilterTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/ProjectFilterTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RelRN; import org.qed.RexRN; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/ProjectMerge.java b/src/main/java/org/qed/RRuleInstances/ProjectMerge.java similarity index 71% rename from src/main/java/org/qed/Generated/RRuleInstances/ProjectMerge.java rename to src/main/java/org/qed/RRuleInstances/ProjectMerge.java index 7458002..6158b60 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/ProjectMerge.java +++ b/src/main/java/org/qed/RRuleInstances/ProjectMerge.java @@ -1,13 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record ProjectMerge() implements RRule { static final RelRN source = RelRN.scan("Source", "Source_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyFilter.java b/src/main/java/org/qed/RRuleInstances/PruneEmptyFilter.java similarity index 90% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyFilter.java rename to src/main/java/org/qed/RRuleInstances/PruneEmptyFilter.java index a0c5eaf..12931c2 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyFilter.java +++ b/src/main/java/org/qed/RRuleInstances/PruneEmptyFilter.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyIntersect.java b/src/main/java/org/qed/RRuleInstances/PruneEmptyIntersect.java similarity index 86% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyIntersect.java rename to src/main/java/org/qed/RRuleInstances/PruneEmptyIntersect.java index fb4938f..8d9d284 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyIntersect.java +++ b/src/main/java/org/qed/RRuleInstances/PruneEmptyIntersect.java @@ -1,8 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; -import org.qed.RexRN; public record PruneEmptyIntersect() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyMinus.java b/src/main/java/org/qed/RRuleInstances/PruneEmptyMinus.java similarity index 85% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyMinus.java rename to src/main/java/org/qed/RRuleInstances/PruneEmptyMinus.java index 09c424c..be9dab9 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyMinus.java +++ b/src/main/java/org/qed/RRuleInstances/PruneEmptyMinus.java @@ -1,8 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; -import org.qed.RexRN; public record PruneEmptyMinus() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyProject.java b/src/main/java/org/qed/RRuleInstances/PruneEmptyProject.java similarity index 91% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyProject.java rename to src/main/java/org/qed/RRuleInstances/PruneEmptyProject.java index 0aac108..e61b68f 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyProject.java +++ b/src/main/java/org/qed/RRuleInstances/PruneEmptyProject.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyUnion.java b/src/main/java/org/qed/RRuleInstances/PruneEmptyUnion.java similarity index 85% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyUnion.java rename to src/main/java/org/qed/RRuleInstances/PruneEmptyUnion.java index 74d3fc5..515a3f7 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneEmptyUnion.java +++ b/src/main/java/org/qed/RRuleInstances/PruneEmptyUnion.java @@ -1,8 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; -import org.qed.RexRN; public record PruneEmptyUnion() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/PruneZeroRowsTable.java b/src/main/java/org/qed/RRuleInstances/PruneZeroRowsTable.java similarity index 82% rename from src/main/java/org/qed/Generated/RRuleInstances/PruneZeroRowsTable.java rename to src/main/java/org/qed/RRuleInstances/PruneZeroRowsTable.java index 393b226..a60fe9b 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/PruneZeroRowsTable.java +++ b/src/main/java/org/qed/RRuleInstances/PruneZeroRowsTable.java @@ -1,8 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.qed.RRule; import org.qed.RelRN; -import org.qed.RexRN; public record PruneZeroRowsTable() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/SemiJoinFilterTranspose.java b/src/main/java/org/qed/RRuleInstances/SemiJoinFilterTranspose.java similarity index 80% rename from src/main/java/org/qed/Generated/RRuleInstances/SemiJoinFilterTranspose.java rename to src/main/java/org/qed/RRuleInstances/SemiJoinFilterTranspose.java index 790c1d2..fbdc617 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/SemiJoinFilterTranspose.java +++ b/src/main/java/org/qed/RRuleInstances/SemiJoinFilterTranspose.java @@ -1,13 +1,9 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record SemiJoinFilterTranspose() implements RRule { static final RelRN left = RelRN.scan("Left", "Left_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/UnionMerge.java b/src/main/java/org/qed/RRuleInstances/UnionMerge.java similarity index 64% rename from src/main/java/org/qed/Generated/RRuleInstances/UnionMerge.java rename to src/main/java/org/qed/RRuleInstances/UnionMerge.java index b71d320..33a7f61 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/UnionMerge.java +++ b/src/main/java/org/qed/RRuleInstances/UnionMerge.java @@ -1,13 +1,7 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; -import kala.collection.Map; -import kala.collection.Seq; -import org.apache.calcite.rel.core.JoinRelType; -import org.apache.calcite.sql.fun.SqlStdOperatorTable; import org.qed.RelRN; -import org.qed.RexRN; import org.qed.RRule; -import org.qed.RuleBuilder; public record UnionMerge() implements RRule { static final RelRN a = RelRN.scan("A", "Common_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/UnionPullUpConstants.java b/src/main/java/org/qed/RRuleInstances/UnionPullUpConstants.java similarity index 64% rename from src/main/java/org/qed/Generated/RRuleInstances/UnionPullUpConstants.java rename to src/main/java/org/qed/RRuleInstances/UnionPullUpConstants.java index 6e3b060..c91efa0 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/UnionPullUpConstants.java +++ b/src/main/java/org/qed/RRuleInstances/UnionPullUpConstants.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.RelNode; import org.qed.RelRN; @@ -8,34 +8,13 @@ import kala.collection.Seq; import kala.tuple.Tuple; -/** - * UnionPullUpConstantsRule: Pulls up constant expressions through Union operators - * - * Pattern: - * Union( - * Project(col1, constant_value, col3), - * Project(col1, constant_value, col3) - * ) - * => - * Project(col1, constant_value, col3, - * Union( - * Project(col1, col3), - * Project(col1, col3) - * ) - * ) - * - * This optimization reduces the Union to only non-constant columns, - * then adds back the constants in a top-level projection. - */ public record UnionPullUpConstants() implements RRule { - - // Base tables for demonstrating the pattern + static final RelRN leftTable = new LeftTableWithConstants(); static final RelRN rightTable = new RightTableWithConstants(); @Override public RelRN before() { - // Union of two projections that both have constants var leftProjection = new LeftProjectionWithConstants(leftTable); var rightProjection = new RightProjectionWithConstants(rightTable); return new UnionWithConstantColumns(leftProjection, rightProjection); @@ -43,54 +22,42 @@ public RelRN before() { @Override public RelRN after() { - // Optimized: constants pulled up, union reduced to non-constant columns var leftProjectionReduced = new LeftProjectionNonConstants(leftTable); var rightProjectionReduced = new RightProjectionNonConstants(rightTable); var reducedUnion = new UnionReducedColumns(leftProjectionReduced, rightProjectionReduced); return new TopProjectionWithConstants(reducedUnion); } - /** - * Left source table - */ public static record LeftTableWithConstants() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // emp_id - Tuple.of(RelType.fromString("VARCHAR", true), false), // emp_name - Tuple.of(RelType.fromString("INTEGER", true), false) // dept_id + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * Right source table - */ public static record RightTableWithConstants() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // emp_id - Tuple.of(RelType.fromString("VARCHAR", true), false), // emp_name - Tuple.of(RelType.fromString("INTEGER", true), false) // dept_id + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false), + Tuple.of(RelType.fromString("INTEGER", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * Left projection with constants: SELECT emp_id, 'ACTIVE' as status, dept_id - */ public static record LeftProjectionWithConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { @@ -98,18 +65,15 @@ public RelNode semantics() { builder.push(input.semantics()); builder.project( - builder.field(0), // emp_id - builder.alias(builder.literal("ACTIVE"), "status"), // constant: 'ACTIVE' - builder.field(2) // dept_id + builder.field(0), + builder.alias(builder.literal("ACTIVE"), "status"), + builder.field(2) ); return builder.build(); } } - - /** - * Right projection with SAME constants: SELECT emp_id, 'ACTIVE' as status, dept_id - */ + public static record RightProjectionWithConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { @@ -117,18 +81,15 @@ public RelNode semantics() { builder.push(input.semantics()); builder.project( - builder.field(0), // emp_id - builder.alias(builder.literal("ACTIVE"), "status"), // same constant: 'ACTIVE' - builder.field(2) // dept_id + builder.field(0), + builder.alias(builder.literal("ACTIVE"), "status"), + builder.field(2) ); return builder.build(); } } - - /** - * Union with constant columns (before optimization) - */ + public static record UnionWithConstantColumns(RelRN left, RelRN right) implements RelRN { @Override public RelNode semantics() { @@ -142,50 +103,36 @@ public RelNode semantics() { return builder.build(); } } - - /** - * Left projection with constants removed: SELECT emp_id, dept_id - */ + public static record LeftProjectionNonConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Project only non-constant columns + builder.project( - builder.field(0), // emp_id - builder.field(2) // dept_id - // status constant removed + builder.field(0), + builder.field(2) ); return builder.build(); } } - - /** - * Right projection with constants removed: SELECT emp_id, dept_id - */ + public static record RightProjectionNonConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Project only non-constant columns builder.project( - builder.field(0), // emp_id - builder.field(2) // dept_id - // status constant removed + builder.field(0), + builder.field(2) ); return builder.build(); } } - - /** - * Union of reduced columns (constants removed) - */ + public static record UnionReducedColumns(RelRN left, RelRN right) implements RelRN { @Override public RelNode semantics() { @@ -194,26 +141,22 @@ public RelNode semantics() { builder.push(left.semantics()); builder.push(right.semantics()); - builder.union(true, 2); // UNION ALL on reduced columns + builder.union(true, 2); return builder.build(); } } - - /** - * Top projection that adds back the constants: SELECT emp_id, 'ACTIVE' as status, dept_id - */ + public static record TopProjectionWithConstants(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Add back the constant in the final projection + builder.project( - builder.field(0), // emp_id (from union) - builder.alias(builder.literal("ACTIVE"), "status"), // constant added back - builder.field(1) // dept_id (from union) + builder.field(0), + builder.alias(builder.literal("ACTIVE"), "status"), + builder.field(1) ); return builder.build(); diff --git a/src/main/java/org/qed/Generated/RRuleInstances/UnionToDistinct.java b/src/main/java/org/qed/RRuleInstances/UnionToDistinct.java similarity index 67% rename from src/main/java/org/qed/Generated/RRuleInstances/UnionToDistinct.java rename to src/main/java/org/qed/RRuleInstances/UnionToDistinct.java index e45c069..94f64ba 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances/UnionToDistinct.java +++ b/src/main/java/org/qed/RRuleInstances/UnionToDistinct.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.RRuleInstances; import org.apache.calcite.rel.RelNode; import org.qed.RelRN; @@ -7,122 +7,84 @@ import org.qed.RelType; import kala.collection.Seq; import kala.tuple.Tuple; - -/** - * UnionToDistinctRule: Transforms UNION DISTINCT into UNION ALL + DISTINCT aggregate - * - * Pattern: Union(all=false, inputs...) => Aggregate(DISTINCT group by all fields)(Union(all=true, inputs...)) - * - * This optimization can be beneficial when the underlying system can handle - * UNION ALL more efficiently than UNION DISTINCT. - */ public record UnionToDistinct() implements RRule { - - // Base tables for the union + static final RelRN leftTable = new LeftSourceTable(); static final RelRN rightTable = new RightSourceTable(); @Override public RelRN before() { - // UNION DISTINCT (all=false) return new DistinctUnion(leftTable, rightTable); } @Override public RelRN after() { - // UNION ALL + DISTINCT aggregate var unionAll = new UnionAll(leftTable, rightTable); return new DistinctAggregate(unionAll); } - /** - * Left source table - */ public static record LeftSourceTable() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // col0 - Tuple.of(RelType.fromString("VARCHAR", true), false) // col1 + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * Right source table (same schema as left for UNION compatibility) - */ + public static record RightSourceTable() implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); var table = builder.createQedTable(Seq.of( - Tuple.of(RelType.fromString("INTEGER", true), false), // col0 - Tuple.of(RelType.fromString("VARCHAR", true), false) // col1 + Tuple.of(RelType.fromString("INTEGER", true), false), + Tuple.of(RelType.fromString("VARCHAR", true), false) )); builder.addTable(table); return builder.scan(table.getName()).build(); } } - - /** - * UNION DISTINCT operation (all=false) - */ + public static record DistinctUnion(RelRN left, RelRN right) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); - - // Push both inputs builder.push(left.semantics()); builder.push(right.semantics()); - - // Create UNION with all=false (DISTINCT) builder.union(false, 2); return builder.build(); } } - - /** - * UNION ALL operation (all=true) - */ + public static record UnionAll(RelRN left, RelRN right) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); - - // Push both inputs + builder.push(left.semantics()); builder.push(right.semantics()); - - // Create UNION with all=true (ALL) + builder.union(true, 2); return builder.build(); } } - - /** - * DISTINCT aggregate - groups by all fields to eliminate duplicates - */ + public static record DistinctAggregate(RelRN input) implements RelRN { @Override public RelNode semantics() { var builder = RuleBuilder.create(); builder.push(input.semantics()); - - // Group by all fields (creates DISTINCT effect) - // For a 2-column table, group by field 0 and field 1 var groupKey = builder.groupKey(builder.field(0), builder.field(1)); - - // No aggregate functions needed - just grouping creates DISTINCT builder.aggregate(groupKey); return builder.build(); diff --git a/src/main/java/org/qed/RelRN.java b/src/main/java/org/qed/RelRN.java index 568fddb..4599997 100644 --- a/src/main/java/org/qed/RelRN.java +++ b/src/main/java/org/qed/RelRN.java @@ -118,9 +118,6 @@ default Empty empty() { return new Empty(this); } - // default Aggregate aggregate(Seq groupSet, Seq aggCalls) { - // return new Aggregate(this, groupSet, aggCalls); - // } record Scan(String name, RelType.VarType ty, boolean unique) implements RelRN { @@ -210,24 +207,6 @@ public RelNode semantics() { } } - // record AggCall(String name, boolean distinct, RelType type, Seq operands) { - // } - - // record Aggregate(org.qed.RelRN source, Seq groupSet, Seq aggCalls) implements org.qed.RelRN { - // @Override - // public RelNode semantics() { - // var builder = RuleBuilder.create(); - // builder.push(source.semantics()); - // var groupKey = builder.groupKey(groupSet.map(RexRN::semantics)); - // var calls = aggCalls.map(agg -> { - // var aggFunc = builder.genericAggregateOp(agg.name(), agg.type()); - // return builder.aggregateCall(aggFunc, agg.distinct(), null, agg.name(), agg.operands().map(RexRN::semantics).asJava()); - // }); - // return builder.aggregate(groupKey, calls).build(); - // } - // } - // Add these methods to RelRN.java: - default Aggregate aggregate(RexRN groupName, AggCall aggCall) { return new Aggregate(this, Seq.of(groupName), Seq.of(aggCall)); } @@ -236,9 +215,6 @@ default Aggregate aggregate(String groupName, String aggName) { return aggregate(groupBy(groupName), aggCall(aggName)); } - // default Aggregate aggregate(RexRN groupField, AggCall aggCall) { - // return aggregate(Seq.of(groupField), Seq.of(aggCall)); - // } default RexRN.GroupBy groupBy(String name) { return new RexRN.GroupBy( @@ -261,25 +237,6 @@ default AggCall aggCall(String name) { ); } - // default AggCall aggCall(String name, String returnTypeName, boolean distinct) { - // return new AggCall( - // name, - // RuleBuilder.create().genericAggregateOp(name, new RelType.VarType(returnTypeName, true)), - // distinct, - // new RelType.VarType(returnTypeName, true), - // fields() - // ); - // } - - // default AggCall aggCall(String name, String returnTypeName, Seq operands) { - // return new AggCall( - // name, - // RuleBuilder.create().genericAggregateOp(name, new RelType.VarType(returnTypeName, true)), - // false, - // new RelType.VarType(returnTypeName, true), - // operands - // ); - // } record AggCall(String name, SqlAggFunction operator, boolean distinct, RelType type, Seq operands) { public AggCall(String name, boolean distinct, RelType type, Seq operands){ diff --git a/src/main/java/org/qed/RexRN.java b/src/main/java/org/qed/RexRN.java index 861a4d3..060c50d 100644 --- a/src/main/java/org/qed/RexRN.java +++ b/src/main/java/org/qed/RexRN.java @@ -66,36 +66,7 @@ default RelRN.AggCall aggCall(String name) { Seq.of(this) ); } - - // default RelRN.AggCall aggCall(String name, String returnTypeName, boolean distinct) { - // return new RelRN.AggCall( - // name, - // RuleBuilder.create().genericAggregateOp(name, new RelType.VarType(returnTypeName, true)), - // distinct, - // new RelType.VarType(returnTypeName, true), - // Seq.of(this) - // ); - // } - - // default RelRN.AggCall aggCall(SqlAggFunction aggFunction, String name, String returnTypeName) { - // return new RelRN.AggCall( - // name, - // aggFunction, - // false, - // new RelType.VarType(returnTypeName, true), - // Seq.of(this) - // ); - // } - - // default RelRN.AggCall aggCall(SqlAggFunction aggFunction, String name, String returnTypeName, boolean distinct) { - // return new RelRN.AggCall( - // name, - // aggFunction, - // distinct, - // new RelType.VarType(returnTypeName, true), - // Seq.of(this) - // ); - // } + record Field(int ordinal, RelRN source) implements RexRN { diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/JoinAssociate.java b/src/main/java/org/qed/UnprovableRRuleInstances/JoinAssociate.java similarity index 98% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/JoinAssociate.java rename to src/main/java/org/qed/UnprovableRRuleInstances/JoinAssociate.java index 059695e..c0c08b7 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/JoinAssociate.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/JoinAssociate.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import kala.collection.Map; import kala.collection.Seq; diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneLeftEmptyJoin.java b/src/main/java/org/qed/UnprovableRRuleInstances/PruneLeftEmptyJoin.java similarity index 87% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneLeftEmptyJoin.java rename to src/main/java/org/qed/UnprovableRRuleInstances/PruneLeftEmptyJoin.java index fbe5979..d6af2aa 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneLeftEmptyJoin.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/PruneLeftEmptyJoin.java @@ -1,9 +1,8 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; import org.qed.RelRN; -import org.qed.RexRN; public record PruneLeftEmptyJoin() implements RRule { static final RelRN left = RelRN.scan("Left", "Left_Type"); diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneRightEmptyJoin.java b/src/main/java/org/qed/UnprovableRRuleInstances/PruneRightEmptyJoin.java similarity index 93% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneRightEmptyJoin.java rename to src/main/java/org/qed/UnprovableRRuleInstances/PruneRightEmptyJoin.java index 4b4b5c0..46527f7 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/PruneRightEmptyJoin.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/PruneRightEmptyJoin.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinJoinTranspose.java b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinJoinTranspose.java similarity index 95% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinJoinTranspose.java rename to src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinJoinTranspose.java index b1a4a3d..3ecc99a 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinJoinTranspose.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinJoinTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinProjectTranspose.java b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinProjectTranspose.java similarity index 94% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinProjectTranspose.java rename to src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinProjectTranspose.java index 71d2dfe..357aef7 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinProjectTranspose.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinProjectTranspose.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule; diff --git a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinRemove.java b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinRemove.java similarity index 92% rename from src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinRemove.java rename to src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinRemove.java index 3b21e3f..27af3ba 100644 --- a/src/main/java/org/qed/Generated/RRuleInstances-unprovable/SemiJoinRemove.java +++ b/src/main/java/org/qed/UnprovableRRuleInstances/SemiJoinRemove.java @@ -1,4 +1,4 @@ -package org.qed.Generated.RRuleInstances; +package org.qed.UnprovableRRuleInstances; import org.apache.calcite.rel.core.JoinRelType; import org.qed.RRule;