Skip to content

Commit

Permalink
[CALCITE-3539] EnumerableDefaults#nestedLoopJoin returns duplicates f…
Browse files Browse the repository at this point in the history
…or JoinType.SEMI
  • Loading branch information
rubenada authored and danny0405 committed Nov 30, 2019
1 parent 67e9367 commit 80f411d
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelCollationTraitDef;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelNodes;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinRelType;
Expand Down Expand Up @@ -89,11 +90,15 @@ public static EnumerableNestedLoopJoin create(
// and have the same cost. To make the results stable between versions of
// the planner, make one of the versions slightly more expensive.
switch (joinType) {
case SEMI:
case ANTI:
// SEMI and ANTI join cannot be flipped
break;
case RIGHT:
rowCount = RelMdUtil.addEpsilon(rowCount);
break;
default:
if (left.getId() > right.getId()) {
if (RelNodes.COMPARATOR.compare(left, right) > 0) {
rowCount = RelMdUtil.addEpsilon(rowCount);
}
}
Expand Down
83 changes: 67 additions & 16 deletions core/src/test/java/org/apache/calcite/runtime/EnumerablesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,39 @@ public class EnumerablesTest {
+ ", " + (v1 == null ? null : v1.name)
+ "}";

private static final Predicate2<Emp, Dept> EQUAL_DEPTNO =
private static final Predicate2<Emp, Dept> EMP_DEPT_EQUAL_DEPTNO =
(e, d) -> e.deptno == d.deptno;
private static final Predicate2<Dept, Emp> DEPT_EMP_EQUAL_DEPTNO =
(d, e) -> d.deptno == e.deptno;

@Test public void testSemiJoin() {
@Test public void testSemiJoinEmp() {
assertThat(
EnumerableDefaults.semiJoin(EMPS, DEPTS, e -> e.deptno, d -> d.deptno,
Functions.identityComparer()).toList().toString(),
equalTo("[Emp(20, Theodore), Emp(20, Sebastian)]"));
}

@Test public void testSemiJoinDept() {
assertThat(
EnumerableDefaults.semiJoin(DEPTS, EMPS, d -> d.deptno, e -> e.deptno,
Functions.identityComparer()).toList().toString(),
equalTo("[Dept(20, Sales)]"));
}

@Test public void testAntiJoinEmp() {
assertThat(
EnumerableDefaults.antiJoin(EMPS, DEPTS, e -> e.deptno, d -> d.deptno,
Functions.identityComparer()).toList().toString(),
equalTo("[Emp(10, Fred), Emp(30, Joe)]"));
}

@Test public void testAntiJoinDept() {
assertThat(
EnumerableDefaults.antiJoin(DEPTS, EMPS, d -> d.deptno, e -> e.deptno,
Functions.identityComparer()).toList().toString(),
equalTo("[Dept(15, Marketing)]"));
}

@Test public void testMergeJoin() {
assertThat(
EnumerableDefaults.mergeJoin(
Expand Down Expand Up @@ -154,61 +177,89 @@ private static <T extends Comparable<T>> Enumerable<T> intersect(
Functions.identitySelector(), (v0, v1) -> v0, false, false);
}

@Test public void testThetaJoin() {
@Test public void testNestedLoopJoin() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.INNER).toList().toString(),
equalTo("[{Theodore, 20, 20, Sales}, {Sebastian, 20, 20, Sales}]"));
}

@Test public void testThetaLeftJoin() {
@Test public void testNestedLoopLeftJoin() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.LEFT).toList().toString(),
equalTo("[{Fred, 10, null, null}, {Theodore, 20, 20, Sales}, "
+ "{Sebastian, 20, 20, Sales}, {Joe, 30, null, null}]"));
}

@Test public void testThetaRightJoin() {
@Test public void testNestedLoopRightJoin() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.RIGHT).toList().toString(),
equalTo("[{Theodore, 20, 20, Sales}, {Sebastian, 20, 20, Sales}, "
+ "{null, null, 15, Marketing}]"));
}

@Test public void testThetaFullJoin() {
@Test public void testNestedLoopFullJoin() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.FULL).toList().toString(),
equalTo("[{Fred, 10, null, null}, {Theodore, 20, 20, Sales}, "
+ "{Sebastian, 20, 20, Sales}, {Joe, 30, null, null}, "
+ "{null, null, 15, Marketing}]"));
}

@Test public void testThetaFullJoinLeftEmpty() {
@Test public void testNestedLoopFullJoinLeftEmpty() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS.take(0), DEPTS, EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS.take(0), DEPTS, EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.FULL)
.orderBy(Functions.identitySelector()).toList().toString(),
equalTo("[{null, null, 15, Marketing}, {null, null, 20, Sales}]"));
}

@Test public void testThetaFullJoinRightEmpty() {
@Test public void testNestedLoopFullJoinRightEmpty() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS.take(0), EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS.take(0), EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.FULL).toList().toString(),
equalTo("[{Fred, 10, null, null}, {Theodore, 20, null, null}, "
+ "{Sebastian, 20, null, null}, {Joe, 30, null, null}]"));
}

@Test public void testThetaFullJoinBothEmpty() {
@Test public void testNestedLoopFullJoinBothEmpty() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS.take(0), DEPTS.take(0), EQUAL_DEPTNO,
EnumerableDefaults.nestedLoopJoin(EMPS.take(0), DEPTS.take(0), EMP_DEPT_EQUAL_DEPTNO,
EMP_DEPT_TO_STRING, JoinType.FULL).toList().toString(),
equalTo("[]"));
}

@Test public void testNestedLoopSemiJoinEmp() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
(e, d) -> e.toString(), JoinType.SEMI).toList().toString(),
equalTo("[Emp(20, Theodore), Emp(20, Sebastian)]"));
}

@Test public void testNestedLoopSemiJoinDept() {
assertThat(
EnumerableDefaults.nestedLoopJoin(DEPTS, EMPS, DEPT_EMP_EQUAL_DEPTNO,
(d, e) -> d.toString(), JoinType.SEMI).toList().toString(),
equalTo("[Dept(20, Sales)]"));
}

@Test public void testNestedLoopAntiJoinEmp() {
assertThat(
EnumerableDefaults.nestedLoopJoin(EMPS, DEPTS, EMP_DEPT_EQUAL_DEPTNO,
(e, d) -> e.toString(), JoinType.ANTI).toList().toString(),
equalTo("[Emp(10, Fred), Emp(30, Joe)]"));
}

@Test public void testNestedLoopAntiJoinDept() {
assertThat(
EnumerableDefaults.nestedLoopJoin(DEPTS, EMPS, DEPT_EMP_EQUAL_DEPTNO,
(d, e) -> d.toString(), JoinType.ANTI).toList().toString(),
equalTo("[Dept(15, Marketing)]"));
}

@Test
@Ignore // TODO fix this
public void testMatch() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,9 @@ public static <TSource, TInner, TResult> Enumerable<TResult> nestedLoopJoin(
rightUnmatched.remove(right);
}
result.add(resultSelector.apply(left, right));
if (joinType == JoinType.SEMI) {
break;
}
}
}
}
Expand Down

0 comments on commit 80f411d

Please sign in to comment.