Skip to content

Commit 349dfdb

Browse files
authored
Merge pull request #31 from qed-solver/dsl-test
Rules under Generated are compilable by CockroachDB. (Not verified to be entirely correct as I have drafted all test cases for each rules)
2 parents 3c5515b + 3e16ff1 commit 349dfdb

158 files changed

Lines changed: 2217 additions & 1073 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/codegen-test.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,4 @@ jobs:
3939
with:
4040
name: generated-code
4141
path: |
42-
src/main/java/org/qed/Generated/*.java
43-
!src/main/java/org/qed/Generated/CalciteTester.java
44-
!src/main/java/org/qed/Generated/CalciteGenerator.java
45-
!src/main/java/org/qed/Generated/CalciteUtilities.java
46-
!src/main/java/org/qed/Generated/EmptyConfig.java
42+
src/main/java/org/qed/Backends/Calcite/Generated/*.java

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@
108108
<version>0.0.7-v5</version>
109109
</dependency>
110110
<dependency>
111-
<groupId>org.reflections</groupId>
112-
<artifactId>reflections</artifactId>
113-
<version>0.10.2</version>
111+
<groupId>com.mysql</groupId>
112+
<artifactId>mysql-connector-j</artifactId>
113+
<version>8.0.33</version>
114114
</dependency>
115115
</dependencies>
116116
</project>

scripts/generate-rule-json.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ CLASSPATH="target/classes:${MAVEN_CP}"
3333
javac -cp "$CLASSPATH" JsonGenerator.java
3434

3535
# Generate JSON for each rule
36-
find src/main/java/org/qed/Generated/RRuleInstances -name '*.java' | while read file; do
36+
find src/main/java/org/qed/RRuleInstances -name '*.java' | while read file; do
3737
className=$(echo "$file" | sed 's|src/main/java/||; s|/|.|g; s|\.java$||')
3838
echo "Generating JSON for: $className"
3939
java -cp ".:$CLASSPATH" JsonGenerator "$className"

scripts/test-codegen.sh

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ echo "" >> $GITHUB_STEP_SUMMARY
88
# Step 1: Generate code for each rule in RRuleInstances
99
# Create temporary Java file for code generation
1010
cat > RuleGenerator.java << 'EOF'
11-
import org.qed.Generated.CalciteTester;
11+
import org.qed.Backends.Calcite.CalciteTester;
1212
import org.qed.*;
1313
import java.nio.file.*;
1414
@@ -34,17 +34,15 @@ CLASSPATH="target/classes:${MAVEN_CP}"
3434
javac -cp "$CLASSPATH" RuleGenerator.java
3535

3636
# Generate code for each rule
37-
find src/main/java/org/qed/Generated/RRuleInstances -name '*.java' -not -path '*/RRuleInstances-unprovable/*' | while read file; do
37+
find src/main/java/org/qed/RRuleInstances -name '*.java' -not -path '*/RRuleInstances-unprovable/*' | while read file; do
3838
className=$(echo "$file" | sed 's|src/main/java/||; s|/|.|g; s|\.java$||')
3939
java -cp ".:$CLASSPATH" RuleGenerator "$className"
4040
done
4141

4242
# Step 2: Check for missing tests
43-
missing_tests=""
44-
missing_count=0
45-
for rule_file in src/main/java/org/qed/Generated/RRuleInstances/*.java; do
43+
for rule_file in src/main/java/org/qed/RRuleInstances/*.java; do
4644
rule_name=$(basename "$rule_file" .java)
47-
if [ ! -f "src/main/java/org/qed/Generated/Tests/${rule_name}Test.java" ]; then
45+
if [ ! -f "src/main/java/org/qed/Backends/Calcite/Tests/${rule_name}Test.java" ]; then
4846
missing_tests="${missing_tests}- ${rule_name}\n"
4947
missing_count=$((missing_count + 1))
5048
fi
@@ -65,7 +63,7 @@ passed_tests=0
6563
total_tests=0
6664
passed_tests=0
6765

68-
for test_file in src/main/java/org/qed/Generated/Tests/*Test.java; do
66+
for test_file in src/main/java/org/qed/Backends/Calcite/Tests/*Test.java; do
6967
class_name=${test_file#src/main/java/}
7068
class_name=${class_name%.java}
7169
class_name=${class_name//\//.}

src/main/java/org/qed/Generated/CalciteGenerator.java renamed to src/main/java/org/qed/Backends/Calcite/CalciteGenerator.java

Lines changed: 3 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.qed.Generated;
1+
package org.qed.Backends.Calcite;
22

33
import kala.collection.Seq;
44
import kala.collection.immutable.ImmutableMap;
@@ -7,7 +7,7 @@
77
import org.qed.CodeGenerator;
88
import org.qed.RelRN;
99
import org.qed.RexRN;
10-
import org.qed.Generated.CalciteGenerator.Env;
10+
import org.qed.Backends.Calcite.CalciteGenerator.Env;
1111

1212
import java.util.concurrent.atomic.AtomicInteger;
1313

@@ -99,7 +99,6 @@ public Env onMatchProj(Env env, RexRN.Proj proj) {
9999
@Override
100100
public Env onMatchJoin(Env env, RelRN.Join join) {
101101
var current_join = "((LogicalJoin) " + env.current() + ")";
102-
// STR."\{join_env.current()}.getJoinType()"
103102
var left_source_env = env.next();
104103
var left_match_env = onMatch(left_source_env, join.left());
105104
var right_source_env = left_match_env.next();
@@ -112,14 +111,9 @@ public Env onMatchJoin(Env env, RelRN.Join join) {
112111

113112
@Override
114113
public Env onMatchAnd(Env env, RexRN.And and) {
115-
// Process each source in the And condition
116114
var current_env = env;
117-
// Use a unique symbol name for the AND condition
118115
String andSymbol = "and_" + env.varId.getAndIncrement();
119-
// Store the current expression as this AND node's symbol
120116
current_env = current_env.symbol(andSymbol, current_env.current());
121-
122-
// Process each child source in the AND condition
123117
for (var source : and.sources()) {
124118
current_env = onMatch(current_env, source);
125119
}
@@ -129,120 +123,84 @@ public Env onMatchAnd(Env env, RexRN.And and) {
129123

130124
@Override
131125
public Env onMatchUnion(Env env, RelRN.Union union) {
132-
// Get the all flag from the union
133126
boolean all = union.all();
134-
135-
// Process each source in the union
136127
var current_env = env;
137128
var skeletons = Seq.empty();
138-
139-
// Process all sources in the sequence
140129
for (var source : union.sources()) {
141130
var next_env = current_env.next();
142131
var source_env = onMatch(next_env, source);
143132
skeletons = skeletons.appended(source_env.skeleton());
144133
current_env = source_env;
145134
}
146-
147-
// Build the input skeletons string for the operand
148135
StringBuilder inputsBuilder = new StringBuilder();
149136
for (int i = 0; i < skeletons.size(); i++) {
150137
if (i > 0) {
151138
inputsBuilder.append(", ");
152139
}
153140
inputsBuilder.append(skeletons.get(i).toString());
154141
}
155-
156-
// Create the union operand with the appropriate class based on the all flag
157142
String operatorClass = all ? "LogicalUnionAll" : "LogicalUnion";
158143
return current_env.grow("operand(" + operatorClass + ".class).inputs(" + inputsBuilder.toString() + ")");
159144
}
160145

161146
@Override
162147
public Env onMatchIntersect(Env env, RelRN.Intersect intersect) {
163-
// Get the all flag from the intersect
164148
boolean all = intersect.all();
165-
166-
// Process each source in the intersect
167149
var current_env = env;
168150
var skeletons = Seq.empty();
169-
170-
// Process all sources in the sequence
171151
for (var source : intersect.sources()) {
172152
var next_env = current_env.next();
173153
var source_env = onMatch(next_env, source);
174154
skeletons = skeletons.appended(source_env.skeleton());
175155
current_env = source_env;
176156
}
177-
178-
// Build the input skeletons string for the operand
179157
StringBuilder inputsBuilder = new StringBuilder();
180158
for (int i = 0; i < skeletons.size(); i++) {
181159
if (i > 0) {
182160
inputsBuilder.append(", ");
183161
}
184162
inputsBuilder.append(skeletons.get(i).toString());
185163
}
186-
187-
// Create the intersect operand with the appropriate class based on the all flag
188164
String operatorClass = all ? "LogicalIntersectAll" : "LogicalIntersect";
189165
return current_env.grow("operand(" + operatorClass + ".class).inputs(" + inputsBuilder.toString() + ")");
190166
}
191167

192168
@Override
193169
public Env onMatchMinus(Env env, RelRN.Minus minus) {
194-
// Get the all flag from the minus
195170
boolean all = minus.all();
196-
197-
// Process each source in the minus
198171
var current_env = env;
199172
var skeletons = Seq.empty();
200-
201-
// Process all sources in the sequence
202173
for (var source : minus.sources()) {
203174
var next_env = current_env.next();
204175
var source_env = onMatch(next_env, source);
205176
skeletons = skeletons.appended(source_env.skeleton());
206177
current_env = source_env;
207178
}
208-
209-
// Build the input skeletons string for the operand
210179
StringBuilder inputsBuilder = new StringBuilder();
211180
for (int i = 0; i < skeletons.size(); i++) {
212181
if (i > 0) {
213182
inputsBuilder.append(", ");
214183
}
215184
inputsBuilder.append(skeletons.get(i).toString());
216185
}
217-
218-
// Create the minus operand
219186
return current_env.grow("operand(LogicalMinus.class).inputs(" + inputsBuilder.toString() + ")");
220187
}
221188

222189
@Override
223190
public Env onMatchField(Env env, RexRN.Field field) {
224-
// Generate a unique symbolic name for this field
225191
String fieldSymbol = "field_" + env.varId.getAndIncrement();
226-
227-
// Store the field expression in the environment's symbol table
228192
return env.symbol(fieldSymbol, env.current());
229193
}
230194

231195
@Override
232196
public Env onMatchTrue(Env env, RexRN literal) {
233-
// Create a unique symbol name for this true literal
234197
String trueSymbol = "true_" + env.varId.getAndIncrement();
235-
236-
// Store the current expression as this true literal's symbol
237198
return env.symbol(trueSymbol, env.current());
238199
}
239200

240201
@Override
241202
public Env onMatchFalse(Env env, RexRN literal) {
242-
// Create a unique symbol name for this false literal
243203
String falseSymbol = "false_" + env.varId.getAndIncrement();
244-
245-
// Store the current expression as this false literal's symbol
246204
return env.symbol(falseSymbol, env.current());
247205
}
248206

@@ -323,37 +281,23 @@ else if (env.rulename.equals("FilterAggregateTranspose")) {
323281

324282
@Override
325283
public Env transformJoinField(Env env, RexRN.JoinField joinField) {
326-
// For JoinCommute: we need to calculate absolute field positions in the swapped join
327-
// Get the original join condition to extract the actual field indices
328284
var origJoinDecl = env.declare("(LogicalJoin) call.rel(0)");
329285
var envWithOrigJoin = origJoinDecl.getValue();
330286
var conditionDecl = envWithOrigJoin.declare("(org.apache.calcite.rex.RexCall) " + origJoinDecl.getKey() + ".getCondition()");
331287
var envWithCondition = conditionDecl.getValue();
332288

333289
if (joinField.ordinal() == 0) {
334-
// Ordinal 0 = Left table in original join
335-
// Extract the left operand field index from original condition
336290
var leftFieldDecl = envWithCondition.declare("((org.apache.calcite.rex.RexInputRef) " + conditionDecl.getKey() + ".getOperands().get(0)).getIndex()");
337291
var envWithLeftField = leftFieldDecl.getValue();
338-
339-
// In swapped join: Left table is now at input 1
340-
// Use field(2, 1, leftFieldIndex) syntax
341292
return envWithLeftField.focus(env.current() + ".field(2, 1, " + leftFieldDecl.getKey() + ")");
342293
}
343294
else if (joinField.ordinal() == 1) {
344-
// Ordinal 1 = Right table in original join
345-
// Extract the right operand field index from original condition
346295
var rightFieldDecl = envWithCondition.declare("((org.apache.calcite.rex.RexInputRef) " + conditionDecl.getKey() + ".getOperands().get(1)).getIndex()");
347296
var envWithRightField = rightFieldDecl.getValue();
348-
349-
// Right table field index needs to be adjusted since it was originally after left table
350297
var leftColCountDecl = envWithRightField.declare("call.rel(1).getRowType().getFieldCount()");
351298
var envWithLeftCount = leftColCountDecl.getValue();
352299
var adjustedRightFieldDecl = envWithLeftCount.declare(rightFieldDecl.getKey() + " - " + leftColCountDecl.getKey());
353300
var envWithAdjustedRightField = adjustedRightFieldDecl.getValue();
354-
355-
// In swapped join: Right table is now at input 0
356-
// Use field(2, 0, adjustedRightFieldIndex) syntax
357301
return envWithAdjustedRightField.focus(env.current() + ".field(2, 0, " + adjustedRightFieldDecl.getKey() + ")");
358302
} else {
359303
throw new UnsupportedOperationException("Unsupported join field ordinal: " + joinField.ordinal());
@@ -429,59 +373,35 @@ public Env transformAnd(Env env, RexRN.And and) {
429373

430374
@Override
431375
public Env transformUnion(Env env, RelRN.Union union) {
432-
// Get the all flag from the union
433376
boolean all = union.all();
434-
435-
// The number of sources
436377
int sourceCount = union.sources().size();
437-
438-
// Transform each source
439378
var current_env = env;
440379
for (var source : union.sources()) {
441380
current_env = transform(current_env, source);
442381
}
443-
444-
// Use the union method with the all flag and source count
445-
// This matches the Calcite RelBuilder.union(boolean all, int n) signature
446382
return current_env.focus(current_env.current() + ".union(" + all + ", " + sourceCount + ")");
447383
}
448384

449385
@Override
450386
public Env transformIntersect(Env env, RelRN.Intersect intersect) {
451-
// Get the all flag from the intersect
452387
boolean all = intersect.all();
453-
454-
// The number of sources
455388
int sourceCount = intersect.sources().size();
456-
457-
// Transform each source
458389
var current_env = env;
459390
for (var source : intersect.sources()) {
460391
current_env = transform(current_env, source);
461392
}
462-
463-
// Use the intersect method with the all flag and source count
464-
// This matches the expected Calcite RelBuilder.intersect(boolean all, int n) signature
465393
String methodName = all ? "intersectAll" : "intersect";
466394
return current_env.focus(current_env.current() + "." + methodName + "(" + all + ", " + sourceCount + ")");
467395
}
468396

469397
@Override
470398
public Env transformMinus(Env env, RelRN.Minus minus) {
471-
// Get the all flag from the minus
472399
boolean all = minus.all();
473-
474-
// The number of sources
475400
int sourceCount = minus.sources().size();
476-
477-
// Transform each source
478401
var current_env = env;
479402
for (var source : minus.sources()) {
480403
current_env = transform(current_env, source);
481404
}
482-
483-
// Use the minus method with the all flag and source count
484-
// This matches the expected Calcite RelBuilder.minus(boolean all, int n) signature
485405
return current_env.focus(current_env.current() + ".minus(" + all + ", " + sourceCount + ")");
486406
}
487407

@@ -530,11 +450,8 @@ public Env transformEmpty(Env env, RelRN.Empty empty) {
530450
@Override
531451
public Env transformCustom(Env env, RelRN custom) {
532452
return switch (custom) {
533-
case org.qed.Generated.RRuleInstances.JoinCommute.ProjectionRelRN projection -> {
534-
// Transform the source first - this builds the join
453+
case org.qed.RRuleInstances.JoinCommute.ProjectionRelRN projection -> {
535454
var sourceEnv = transform(env, projection.source());
536-
537-
// Get original table column counts
538455
var leftTableDecl = sourceEnv.declare("call.rel(1)");
539456
var envWithLeftTable = leftTableDecl.getValue();
540457
var rightTableDecl = envWithLeftTable.declare("call.rel(2)");
@@ -544,26 +461,18 @@ public Env transformCustom(Env env, RelRN custom) {
544461
var envWithLeftCount = leftColCountDecl.getValue();
545462
var rightColCountDecl = envWithLeftCount.declare(rightTableDecl.getKey() + ".getRowType().getFieldCount()");
546463
var envWithRightCount = rightColCountDecl.getValue();
547-
548-
// Create the projection indices as a List<Integer>
549464
var projectionIndicesDecl = envWithRightCount.declare(
550465
"java.util.stream.IntStream.concat(" +
551-
// Left columns: rightColCount + 0, rightColCount + 1, ..., rightColCount + leftColCount - 1
552466
"java.util.stream.IntStream.range(" + rightColCountDecl.getKey() + ", " +
553467
rightColCountDecl.getKey() + " + " + leftColCountDecl.getKey() + "), " +
554-
// Right columns: 0, 1, ..., rightColCount - 1
555468
"java.util.stream.IntStream.range(0, " + rightColCountDecl.getKey() + ")" +
556469
").boxed().collect(java.util.stream.Collectors.toList())"
557470
);
558471
var envWithProjectionIndices = projectionIndicesDecl.getValue();
559-
560-
// Convert List<Integer> to field references using RelBuilder.fields()
561472
var fieldRefsDecl = envWithProjectionIndices.declare(
562473
sourceEnv.current() + ".fields(" + projectionIndicesDecl.getKey() + ")"
563474
);
564475
var envWithFieldRefs = fieldRefsDecl.getValue();
565-
566-
// Apply projection using the field references list
567476
yield envWithFieldRefs.focus(sourceEnv.current() + ".project(" + fieldRefsDecl.getKey() + ")");
568477
}
569478
default -> unimplementedTransform(env, custom);

0 commit comments

Comments
 (0)