Skip to content

Commit 7705243

Browse files
authored
feat(isthmus): always emit Cross relation when possible (#367)
BREAKING CHANGE: removed CrossJoinPolicy from FeatureBoard
1 parent dcad8c0 commit 7705243

File tree

5 files changed

+25
-72
lines changed

5 files changed

+25
-72
lines changed

isthmus-cli/src/main/java/io/substrait/isthmus/cli/IsthmusEntryPoint.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import io.substrait.isthmus.ImmutableFeatureBoard;
1414
import io.substrait.isthmus.SqlExpressionToSubstrait;
1515
import io.substrait.isthmus.SqlToSubstrait;
16-
import io.substrait.isthmus.SubstraitRelVisitor.CrossJoinPolicy;
1716
import io.substrait.proto.ExtendedExpression;
1817
import io.substrait.proto.Plan;
1918
import java.io.IOException;
@@ -66,11 +65,6 @@ enum OutputFormat {
6665
description = "One of built-in Calcite SQL compatibility modes: ${COMPLETION-CANDIDATES}")
6766
private SqlConformanceEnum sqlConformanceMode = SqlConformanceEnum.DEFAULT;
6867

69-
@Option(
70-
names = {"--crossjoinpolicy"},
71-
description = "One of built-in Calcite SQL compatibility modes: ${COMPLETION-CANDIDATES}")
72-
private CrossJoinPolicy crossJoinPolicy = CrossJoinPolicy.KEEP_AS_CROSS_JOIN;
73-
7468
@Option(
7569
names = {"--unquotedcasing"},
7670
description = "Calcite's casing policy for unquoted identifiers: ${COMPLETION-CANDIDATES}")
@@ -127,7 +121,6 @@ FeatureBoard buildFeatureBoard() {
127121
return ImmutableFeatureBoard.builder()
128122
.allowsSqlBatch(allowMultiStatement)
129123
.sqlConformanceMode(sqlConformanceMode)
130-
.crossJoinPolicy(crossJoinPolicy)
131124
.unquotedCasing(unquotedCasing)
132125
.build();
133126
}

isthmus-cli/src/test/java/io/substrait/isthmus/cli/IsthmusEntryPointTest.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import static org.junit.jupiter.api.Assertions.assertTrue;
77

88
import io.substrait.isthmus.FeatureBoard;
9-
import io.substrait.isthmus.SubstraitRelVisitor.CrossJoinPolicy;
109
import org.apache.calcite.sql.validate.SqlConformance;
1110
import org.apache.calcite.sql.validate.SqlConformanceEnum;
1211
import org.junit.jupiter.api.Test;
@@ -23,24 +22,18 @@ void defaultFeatureBoard() {
2322
FeatureBoard features = isthmusEntryPoint.buildFeatureBoard();
2423
assertFalse(features.allowsSqlBatch());
2524
assertEquals(SqlConformanceEnum.DEFAULT, features.sqlConformanceMode());
26-
assertEquals(CrossJoinPolicy.KEEP_AS_CROSS_JOIN, features.crossJoinPolicy());
2725
}
2826

2927
/** Test that the command line options are correctly parsed into the {@link FeatureBoard}. */
3028
@Test
3129
void customFeatureBoard() {
3230
IsthmusEntryPoint isthmusEntryPoint = new IsthmusEntryPoint();
3331
new CommandLine(isthmusEntryPoint)
34-
.parseArgs(
35-
"--multistatement",
36-
"--sqlconformancemode=SQL_SERVER_2008",
37-
"--crossjoinpolicy=CONVERT_TO_INNER_JOIN",
38-
"SELECT * FROM foo");
32+
.parseArgs("--multistatement", "--sqlconformancemode=SQL_SERVER_2008", "SELECT * FROM foo");
3933
FeatureBoard features = isthmusEntryPoint.buildFeatureBoard();
4034
assertTrue(features.allowsSqlBatch());
4135
assertEquals(
4236
(SqlConformance) SqlConformanceEnum.SQL_SERVER_2008, features.sqlConformanceMode());
43-
assertEquals(CrossJoinPolicy.CONVERT_TO_INNER_JOIN, features.crossJoinPolicy());
4437
}
4538

4639
/**

isthmus/src/main/java/io/substrait/isthmus/FeatureBoard.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.substrait.isthmus;
22

3-
import io.substrait.isthmus.SubstraitRelVisitor.CrossJoinPolicy;
43
import org.apache.calcite.avatica.util.Casing;
54
import org.apache.calcite.sql.validate.SqlConformance;
65
import org.apache.calcite.sql.validate.SqlConformanceEnum;
@@ -33,14 +32,6 @@ public SqlConformance sqlConformanceMode() {
3332
return SqlConformanceEnum.DEFAULT;
3433
}
3534

36-
/**
37-
* @return the selected cross join policy
38-
*/
39-
@Value.Default
40-
public CrossJoinPolicy crossJoinPolicy() {
41-
return CrossJoinPolicy.KEEP_AS_CROSS_JOIN;
42-
}
43-
4435
/**
4536
* @return Calcite's identifier casing policy for unquoted identifiers.
4637
*/

isthmus/src/main/java/io/substrait/isthmus/SubstraitRelVisitor.java

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.substrait.isthmus;
22

3-
import static io.substrait.isthmus.SubstraitRelVisitor.CrossJoinPolicy.KEEP_AS_CROSS_JOIN;
4-
53
import io.substrait.expression.Expression;
64
import io.substrait.expression.ExpressionCreator;
75
import io.substrait.expression.FieldReference;
@@ -183,9 +181,8 @@ public Rel visit(org.apache.calcite.rel.core.Join join) {
183181
"Unsupported join type: " + join.getJoinType());
184182
};
185183

186-
if (joinType == Join.JoinType.INNER
187-
&& TRUE.equals(condition)
188-
&& featureBoard.crossJoinPolicy().equals(KEEP_AS_CROSS_JOIN)) {
184+
// An INNER JOIN with a join condition of TRUE can be encoded as a Substrait Cross relation
185+
if (joinType == Join.JoinType.INNER && TRUE.equals(condition)) {
189186
return Cross.builder().left(left).right(right).build();
190187
}
191188
return Join.builder().condition(condition).joinType(joinType).left(left).right(right).build();
@@ -398,29 +395,4 @@ private static Rel convert(
398395
visitor.popFieldAccessDepthMap(rel);
399396
return visitor.apply(rel);
400397
}
401-
402-
public enum CrossJoinPolicy {
403-
KEEP_AS_CROSS_JOIN,
404-
CONVERT_TO_INNER_JOIN
405-
};
406-
407-
public static class Options {
408-
private final CrossJoinPolicy crossJoinPolicy;
409-
410-
public Options() {
411-
this(CrossJoinPolicy.CONVERT_TO_INNER_JOIN);
412-
}
413-
414-
public Options(CrossJoinPolicy crossJoinPolicy) {
415-
this.crossJoinPolicy = crossJoinPolicy;
416-
}
417-
418-
/**
419-
* Returns the {@code crossJoinAsInnerJoin} option. Controls whether to cross joins are
420-
* represented as inner joins with a true condition.
421-
*/
422-
public CrossJoinPolicy getCrossJoinPolicy() {
423-
return crossJoinPolicy;
424-
}
425-
}
426398
}

isthmus/src/test/java/io/substrait/isthmus/ProtoPlanConverterTest.java

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.substrait.isthmus;
22

3-
import static io.substrait.isthmus.SubstraitRelVisitor.CrossJoinPolicy.KEEP_AS_CROSS_JOIN;
43
import static org.junit.jupiter.api.Assertions.assertEquals;
54

65
import io.substrait.isthmus.utils.SetUtils;
@@ -73,36 +72,41 @@ public void filter() throws IOException, SqlParseException {
7372
@Test
7473
public void crossJoin() throws IOException, SqlParseException {
7574
int[] counter = new int[1];
76-
var visitor =
75+
var crossJoinCountingVisitor =
7776
new RelCopyOnWriteVisitor<RuntimeException>() {
7877
public Optional<Rel> visit(Cross cross) throws RuntimeException {
7978
counter[0]++;
8079
return super.visit(cross);
8180
}
8281
};
83-
FeatureBoard featureBoard =
84-
ImmutableFeatureBoard.builder().crossJoinPolicy(KEEP_AS_CROSS_JOIN).build();
82+
var featureBoard = ImmutableFeatureBoard.builder().build();
83+
8584
Plan plan1 =
8685
assertProtoPlanRoundrip(
87-
"select\n"
88-
+ " c.c_custKey,\n"
89-
+ " o.o_custkey\n"
90-
+ "from\n"
91-
+ " \"customer\" c cross join\n"
92-
+ " \"orders\" o",
86+
"""
87+
select
88+
c.c_custKey,
89+
o.o_custkey
90+
from
91+
"customer" c cross join
92+
"orders" o
93+
""",
9394
new SqlToSubstrait(featureBoard));
94-
plan1.getRoots().forEach(t -> t.getInput().accept(visitor));
95+
plan1.getRoots().forEach(t -> t.getInput().accept(crossJoinCountingVisitor));
9596
assertEquals(1, counter[0]);
97+
9698
Plan plan2 =
9799
assertProtoPlanRoundrip(
98-
"select\n"
99-
+ " c.c_custKey,\n"
100-
+ " o.o_custkey\n"
101-
+ "from\n"
102-
+ " \"customer\" c,\n"
103-
+ " \"orders\" o",
100+
"""
101+
select
102+
c.c_custKey,
103+
o.o_custkey
104+
from
105+
"customer" c,
106+
"orders" o
107+
""",
104108
new SqlToSubstrait(featureBoard));
105-
plan2.getRoots().forEach(t -> t.getInput().accept(visitor));
109+
plan2.getRoots().forEach(t -> t.getInput().accept(crossJoinCountingVisitor));
106110
assertEquals(2, counter[0]);
107111
}
108112

0 commit comments

Comments
 (0)