Repository: drill
Updated Branches:
refs/heads/merge_09_19_16 [created] a29f1e292
DRILL-4927: Add support for Null Equality Joins
These changes are a subset of the original pull request from DRILL-4539 (PR-462).
- Added changes to support Null Equality Joins;
- Created tests for it.
close apache/drill#603
Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/a29f1e29
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/a29f1e29
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/a29f1e29
Branch: refs/heads/merge_09_19_16
Commit: a29f1e292fc8068ce13d336ba93abcc64f31da26
Parents: 46b424c
Author: Roman Kulyk <rom.kulyk@gmail.com>
Authored: Tue Oct 4 13:58:13 2016 +0000
Committer: Aman Sinha <asinha@maprtech.com>
Committed: Tue Oct 11 23:02:26 2016 -0700
----------------------------------------------------------------------
.../exec/physical/impl/join/JoinUtils.java | 37 ++++-----
.../exec/planner/common/DrillJoinRelBase.java | 9 ++-
.../planner/logical/DrillFilterJoinRules.java | 3 +-
.../exec/planner/logical/DrillJoinRel.java | 2 +-
.../exec/planner/logical/DrillJoinRule.java | 53 ++++++-------
.../exec/planner/physical/HashJoinPrel.java | 2 +-
.../exec/planner/physical/JoinPruleBase.java | 5 +-
.../exec/planner/physical/MergeJoinPrel.java | 2 +-
.../planner/physical/NestedLoopJoinPrel.java | 2 +-
.../planner/physical/NestedLoopJoinPrule.java | 5 +-
.../planner/sql/handlers/DefaultSqlHandler.java | 6 +-
.../java/org/apache/drill/TestJoinNullable.java | 79 ++++++++++++++++++++
pom.xml | 2 +-
13 files changed, 149 insertions(+), 58 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/join/JoinUtils.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/join/JoinUtils.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/join/JoinUtils.java
index 61640bc..be363d2 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/join/JoinUtils.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/join/JoinUtils.java
@@ -86,17 +86,19 @@ public class JoinUtils {
* Check if the given RelNode contains any Cartesian join.
* Return true if find one. Otherwise, return false.
*
- * @param relNode the RelNode to be inspected.
- * @param leftKeys a list used for the left input into the join which has
- * equi-join keys. It can be empty or not (but not null),
- * this method will clear this list before using it.
- * @param rightKeys a list used for the right input into the join which has
- * equi-join keys. It can be empty or not (but not null),
- * this method will clear this list before using it.
- * @return Return true if the given relNode contains Cartesian join.
- * Otherwise, return false
+ * @param relNode the RelNode to be inspected.
+ * @param leftKeys a list used for the left input into the join which has
+ * equi-join keys. It can be empty or not (but not null),
+ * this method will clear this list before using it.
+ * @param rightKeys a list used for the right input into the join which has
+ * equi-join keys. It can be empty or not (but not null),
+ * this method will clear this list before using it.
+ * @param filterNulls The join key positions for which null values will not
+ * match.
+ * @return Return true if the given relNode contains Cartesian join.
+ * Otherwise, return false
*/
- public static boolean checkCartesianJoin(RelNode relNode, List<Integer> leftKeys,
List<Integer> rightKeys) {
+ public static boolean checkCartesianJoin(RelNode relNode, List<Integer> leftKeys,
List<Integer> rightKeys, List<Boolean> filterNulls) {
if (relNode instanceof Join) {
leftKeys.clear();
rightKeys.clear();
@@ -105,20 +107,20 @@ public class JoinUtils {
RelNode left = joinRel.getLeft();
RelNode right = joinRel.getRight();
- RexNode remaining = RelOptUtil.splitJoinCondition(left, right, joinRel.getCondition(),
leftKeys, rightKeys);
- if(joinRel.getJoinType() == JoinRelType.INNER) {
- if(leftKeys.isEmpty() || rightKeys.isEmpty()) {
+ RexNode remaining = RelOptUtil.splitJoinCondition(left, right, joinRel.getCondition(),
leftKeys, rightKeys, filterNulls);
+ if (joinRel.getJoinType() == JoinRelType.INNER) {
+ if (leftKeys.isEmpty() || rightKeys.isEmpty()) {
return true;
}
} else {
- if(!remaining.isAlwaysTrue() || leftKeys.isEmpty() || rightKeys.isEmpty()) {
+ if (!remaining.isAlwaysTrue() || leftKeys.isEmpty() || rightKeys.isEmpty()) {
return true;
}
}
}
for (RelNode child : relNode.getInputs()) {
- if(checkCartesianJoin(child, leftKeys, rightKeys)) {
+ if (checkCartesianJoin(child, leftKeys, rightKeys, filterNulls)) {
return true;
}
}
@@ -249,13 +251,14 @@ public class JoinUtils {
}
public static JoinCategory getJoinCategory(RelNode left, RelNode right, RexNode condition,
- List<Integer> leftKeys, List<Integer> rightKeys) {
+ List<Integer> leftKeys, List<Integer> rightKeys, List<Boolean> filterNulls)
{
if (condition.isAlwaysTrue()) {
return JoinCategory.CARTESIAN;
}
leftKeys.clear();
rightKeys.clear();
- RexNode remaining = RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys);
+ filterNulls.clear();
+ RexNode remaining = RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys,
filterNulls);
if (!remaining.isAlwaysTrue() || (leftKeys.size() == 0 || rightKeys.size() == 0) ) {
// for practical purposes these cases could be treated as inequality
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillJoinRelBase.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillJoinRelBase.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillJoinRelBase.java
index 2d6f7d6..6bd0e9c 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillJoinRelBase.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/common/DrillJoinRelBase.java
@@ -48,7 +48,12 @@ import com.google.common.collect.Lists;
*/
public abstract class DrillJoinRelBase extends Join implements DrillRelNode {
protected List<Integer> leftKeys = Lists.newArrayList();
- protected List<Integer> rightKeys = Lists.newArrayList() ;
+ protected List<Integer> rightKeys = Lists.newArrayList();
+
+ /**
+ * The join key positions for which null values will not match.
+ */
+ protected List<Boolean> filterNulls = Lists.newArrayList();
private final double joinRowFactor;
public DrillJoinRelBase(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode
right, RexNode condition,
@@ -59,7 +64,7 @@ public abstract class DrillJoinRelBase extends Join implements DrillRelNode
{
@Override
public RelOptCost computeSelfCost(RelOptPlanner planner) {
- JoinCategory category = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys);
+ JoinCategory category = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys,
filterNulls);
if (category == JoinCategory.CARTESIAN || category == JoinCategory.INEQUALITY) {
if (PrelUtil.getPlannerSettings(planner).isNestedLoopJoinEnabled()) {
if (PrelUtil.getPlannerSettings(planner).isNlJoinForScalarOnly()) {
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillFilterJoinRules.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillFilterJoinRules.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillFilterJoinRules.java
index 2affb0c..0c1fdb3 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillFilterJoinRules.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillFilterJoinRules.java
@@ -53,8 +53,9 @@ public class DrillFilterJoinRules {
List<RexNode> tmpLeftKeys = Lists.newArrayList();
List<RexNode> tmpRightKeys = Lists.newArrayList();
List<RelDataTypeField> sysFields = Lists.newArrayList();
+ List<Integer> filterNulls = Lists.newArrayList();
- RexNode remaining = RelOptUtil.splitJoinCondition(sysFields, join.getLeft(), join.getRight(),
exp, tmpLeftKeys, tmpRightKeys, null, null);
+ RexNode remaining = RelOptUtil.splitJoinCondition(sysFields, join.getLeft(), join.getRight(),
exp, tmpLeftKeys, tmpRightKeys, filterNulls, null);
if (remaining.isAlwaysTrue()) {
return true;
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRel.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRel.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRel.java
index ca08363..18abdd5 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRel.java
@@ -52,7 +52,7 @@ public class DrillJoinRel extends DrillJoinRelBase implements DrillRel {
JoinRelType joinType) {
super(cluster, traits, left, right, condition, joinType);
assert traits.contains(DrillRel.DRILL_LOGICAL);
- RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys);
+ RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys, filterNulls);
}
public DrillJoinRel(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right,
RexNode condition,
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRule.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRule.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRule.java
index f3b9f6a..d41ae72 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRule.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/logical/DrillJoinRule.java
@@ -63,14 +63,15 @@ public class DrillJoinRule extends RelOptRule {
List<Integer> leftKeys = Lists.newArrayList();
List<Integer> rightKeys = Lists.newArrayList();
+ List<Boolean> filterNulls = Lists.newArrayList();
int numLeftFields = convertedLeft.getRowType().getFieldCount();
boolean addFilter = false;
RexNode origJoinCondition = join.getCondition();
RexNode newJoinCondition = origJoinCondition;
- RexNode remaining = RelOptUtil.splitJoinCondition(convertedLeft, convertedRight, origJoinCondition,
leftKeys, rightKeys);
- boolean hasEquijoins = (leftKeys.size() == rightKeys.size() && leftKeys.size()
> 0) ? true : false;
+ RexNode remaining = RelOptUtil.splitJoinCondition(convertedLeft, convertedRight, origJoinCondition,
leftKeys, rightKeys, filterNulls);
+ boolean hasEquijoins = leftKeys.size() == rightKeys.size() && leftKeys.size()
> 0;
// If the join involves equijoins and non-equijoins, then we can process the non-equijoins
through
// a filter right after the join
@@ -79,35 +80,15 @@ public class DrillJoinRule extends RelOptRule {
if (! remaining.isAlwaysTrue()) {
if (hasEquijoins && join.getJoinType()== JoinRelType.INNER) {
addFilter = true;
- List<RexNode> equijoinList = Lists.newArrayList();
- List<RelDataTypeField> leftTypes = convertedLeft.getRowType().getFieldList();
- List<RelDataTypeField> rightTypes = convertedRight.getRowType().getFieldList();
- RexBuilder builder = join.getCluster().getRexBuilder();
-
- for (int i=0; i < leftKeys.size(); i++) {
- int leftKeyOrdinal = leftKeys.get(i).intValue();
- int rightKeyOrdinal = rightKeys.get(i).intValue();
-
- equijoinList.add(builder.makeCall(
- SqlStdOperatorTable.EQUALS,
- builder.makeInputRef(leftTypes.get(leftKeyOrdinal).getType(), leftKeyOrdinal),
- builder.makeInputRef(rightTypes.get(rightKeyOrdinal).getType(), rightKeyOrdinal
+ numLeftFields)
- ) );
- }
- newJoinCondition = RexUtil.composeConjunction(builder, equijoinList, false);
- } else {
-// tracer.warning("Non-equijoins are only supported in the presence of an equijoin.");
-// return;
+ newJoinCondition = buildJoinCondition(convertedLeft, convertedRight, leftKeys, rightKeys,
filterNulls, join.getCluster().getRexBuilder());
}
+ } else {
+ newJoinCondition = buildJoinCondition(convertedLeft, convertedRight, leftKeys, rightKeys,
filterNulls, join.getCluster().getRexBuilder());
}
- //else {
- //
- // return;
- // }
try {
if (!addFilter) {
- RelNode joinRel = new DrillJoinRel(join.getCluster(), traits, convertedLeft, convertedRight,
origJoinCondition,
+ RelNode joinRel = new DrillJoinRel(join.getCluster(), traits, convertedLeft, convertedRight,
newJoinCondition,
join.getJoinType(), leftKeys, rightKeys);
call.transformTo(joinRel);
} else {
@@ -119,4 +100,24 @@ public class DrillJoinRule extends RelOptRule {
tracer.warning(e.toString());
}
}
+
+ private RexNode buildJoinCondition(RelNode convertedLeft, RelNode convertedRight, List<Integer>
leftKeys,
+ List<Integer> rightKeys, List<Boolean> filterNulls, RexBuilder builder)
{
+ List<RexNode> equijoinList = Lists.newArrayList();
+ final int numLeftFields = convertedLeft.getRowType().getFieldCount();
+ List<RelDataTypeField> leftTypes = convertedLeft.getRowType().getFieldList();
+ List<RelDataTypeField> rightTypes = convertedRight.getRowType().getFieldList();
+
+ for (int i=0; i < leftKeys.size(); i++) {
+ int leftKeyOrdinal = leftKeys.get(i).intValue();
+ int rightKeyOrdinal = rightKeys.get(i).intValue();
+
+ equijoinList.add(builder.makeCall(
+ filterNulls.get(i) ? SqlStdOperatorTable.EQUALS : SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
+ builder.makeInputRef(leftTypes.get(leftKeyOrdinal).getType(), leftKeyOrdinal),
+ builder.makeInputRef(rightTypes.get(rightKeyOrdinal).getType(), rightKeyOrdinal
+ numLeftFields)
+ ));
+ }
+ return RexUtil.composeConjunction(builder, equijoinList, false);
+ }
}
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java
index dc21bdb..ec023f6 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/HashJoinPrel.java
@@ -52,7 +52,7 @@ public class HashJoinPrel extends JoinPrel {
JoinRelType joinType, boolean swapped) throws InvalidRelException {
super(cluster, traits, left, right, condition, joinType);
this.swapped = swapped;
- joincategory = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys);
+ joincategory = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys,
filterNulls);
}
@Override
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java
index fd0ea69..4342478 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java
@@ -53,8 +53,9 @@ public abstract class JoinPruleBase extends Prule {
protected boolean checkPreconditions(DrillJoinRel join, RelNode left, RelNode right,
PlannerSettings settings) {
List<Integer> leftKeys = Lists.newArrayList();
- List<Integer> rightKeys = Lists.newArrayList() ;
- JoinCategory category = JoinUtils.getJoinCategory(left, right, join.getCondition(), leftKeys,
rightKeys);
+ List<Integer> rightKeys = Lists.newArrayList();
+ List<Boolean> filterNulls = Lists.newArrayList();
+ JoinCategory category = JoinUtils.getJoinCategory(left, right, join.getCondition(), leftKeys,
rightKeys, filterNulls);
if (category == JoinCategory.CARTESIAN || category == JoinCategory.INEQUALITY) {
return false;
}
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/MergeJoinPrel.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/MergeJoinPrel.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/MergeJoinPrel.java
index e7141d9..423f7e5 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/MergeJoinPrel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/MergeJoinPrel.java
@@ -48,7 +48,7 @@ public class MergeJoinPrel extends JoinPrel {
public MergeJoinPrel(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right,
RexNode condition,
JoinRelType joinType) throws InvalidRelException {
super(cluster, traits, left, right, condition, joinType);
- joincategory = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys);
+ joincategory = JoinUtils.getJoinCategory(left, right, condition, leftKeys, rightKeys,
filterNulls);
}
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrel.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrel.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrel.java
index b35017e..d229b33 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrel.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrel.java
@@ -45,7 +45,7 @@ public class NestedLoopJoinPrel extends JoinPrel {
public NestedLoopJoinPrel(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode
right, RexNode condition,
JoinRelType joinType) throws InvalidRelException {
super(cluster, traits, left, right, condition, joinType);
- RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys);
+ RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys, filterNulls);
}
@Override
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrule.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrule.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrule.java
index 24be433..2cda15a 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrule.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/NestedLoopJoinPrule.java
@@ -54,8 +54,9 @@ public class NestedLoopJoinPrule extends JoinPruleBase {
}
List<Integer> leftKeys = Lists.newArrayList();
- List<Integer> rightKeys = Lists.newArrayList() ;
- JoinCategory category = JoinUtils.getJoinCategory(left, right, join.getCondition(), leftKeys,
rightKeys);
+ List<Integer> rightKeys = Lists.newArrayList();
+ List<Boolean> filterNulls = Lists.newArrayList();
+ JoinCategory category = JoinUtils.getJoinCategory(left, right, join.getCondition(), leftKeys,
rightKeys, filterNulls);
if (category == JoinCategory.EQUALITY
&& (settings.isHashJoinEnabled() || settings.isMergeJoinEnabled())) {
return false;
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java
index e5359a3..2d0c069 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/handlers/DefaultSqlHandler.java
@@ -269,7 +269,7 @@ public class DefaultSqlHandler extends AbstractSqlHandler {
} catch (RelOptPlanner.CannotPlanException ex) {
logger.error(ex.getMessage());
- if(JoinUtils.checkCartesianJoin(relNode, new ArrayList<Integer>(), new ArrayList<Integer>()))
{
+ if(JoinUtils.checkCartesianJoin(relNode, new ArrayList<Integer>(), new ArrayList<Integer>(),
new ArrayList<Boolean>())) {
throw new UnsupportedRelOperatorException("This query cannot be planned possibly
due to either a cartesian join or an inequality join");
} else {
throw ex;
@@ -428,7 +428,7 @@ public class DefaultSqlHandler extends AbstractSqlHandler {
} catch (RelOptPlanner.CannotPlanException ex) {
logger.error(ex.getMessage());
- if(JoinUtils.checkCartesianJoin(drel, new ArrayList<Integer>(), new ArrayList<Integer>()))
{
+ if(JoinUtils.checkCartesianJoin(drel, new ArrayList<Integer>(), new ArrayList<Integer>(),
new ArrayList<Boolean>())) {
throw new UnsupportedRelOperatorException("This query cannot be planned possibly
due to either a cartesian join or an inequality join");
} else {
throw ex;
@@ -451,7 +451,7 @@ public class DefaultSqlHandler extends AbstractSqlHandler {
} catch (RelOptPlanner.CannotPlanException ex) {
logger.error(ex.getMessage());
- if(JoinUtils.checkCartesianJoin(drel, new ArrayList<Integer>(), new ArrayList<Integer>()))
{
+ if(JoinUtils.checkCartesianJoin(drel, new ArrayList<Integer>(), new ArrayList<Integer>(),
new ArrayList<Boolean>())) {
throw new UnsupportedRelOperatorException("This query cannot be planned possibly
due to either a cartesian join or an inequality join");
} else {
throw ex;
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/exec/java-exec/src/test/java/org/apache/drill/TestJoinNullable.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/test/java/org/apache/drill/TestJoinNullable.java b/exec/java-exec/src/test/java/org/apache/drill/TestJoinNullable.java
index 320a992..b34c7fd 100644
--- a/exec/java-exec/src/test/java/org/apache/drill/TestJoinNullable.java
+++ b/exec/java-exec/src/test/java/org/apache/drill/TestJoinNullable.java
@@ -414,4 +414,83 @@ public class TestJoinNullable extends BaseTestQuery{
assertEquals("Number of output rows", expectedRecordCount, actualRecordCount);
}
+ @Test
+ public void testNullEqualInWhereConditionHashJoin() throws Exception {
+ final String query = "SELECT * FROM "
+ + "cp.`jsoninput/nullableOrdered1.json` t1, "
+ + "cp.`jsoninput/nullableOrdered2.json` t2 "
+ + "WHERE t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)";
+ nullEqualJoinHelper(query);
+ }
+
+ @Test
+ public void testNullEqualInWhereConditionMergeJoin() throws Exception {
+ try {
+ test("alter session set `planner.enable_hashjoin` = false");
+ final String query = "SELECT * FROM "
+ + "cp.`jsoninput/nullableOrdered1.json` t1, "
+ + "cp.`jsoninput/nullableOrdered2.json` t2 "
+ + "WHERE t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)";
+ nullEqualJoinHelper(query);
+ } finally {
+ test("alter session set `planner.enable_hashjoin` = true");
+ }
+ }
+
+ @Test
+ public void testNullEqualHashJoin() throws Exception {
+ final String query = "SELECT * FROM "
+ + "cp.`jsoninput/nullableOrdered1.json` t1 JOIN "
+ + "cp.`jsoninput/nullableOrdered2.json` t2 "
+ + "ON t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)";
+ nullEqualJoinHelper(query);
+ }
+
+ @Test
+ public void testNullEqualMergeJoin() throws Exception {
+ try {
+ test("alter session set `planner.enable_hashjoin` = false");
+ final String query = "SELECT * FROM "
+ + "cp.`jsoninput/nullableOrdered1.json` t1 JOIN "
+ + "cp.`jsoninput/nullableOrdered2.json` t2 "
+ + "ON t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)";
+ nullEqualJoinHelper(query);
+ } finally {
+ test("alter session set `planner.enable_hashjoin` = true");
+ }
+ }
+
+ public void nullEqualJoinHelper(final String query) throws Exception {
+ testBuilder()
+ .sqlQuery(query)
+ .unOrdered()
+ .baselineColumns("key", "data", "data0", "key0")
+ .baselineValues(null, "L_null_1", "R_null_1", null)
+ .baselineValues(null, "L_null_2", "R_null_1", null)
+ .baselineValues("A", "L_A_1", "R_A_1", "A")
+ .baselineValues("A", "L_A_2", "R_A_1", "A")
+ .baselineValues(null, "L_null_1", "R_null_2", null)
+ .baselineValues(null, "L_null_2", "R_null_2", null)
+ .baselineValues(null, "L_null_1", "R_null_3", null)
+ .baselineValues(null, "L_null_2", "R_null_3", null)
+ .go();
+ }
+
+ @Test
+ public void withNullEqualAdditionFilter() throws Exception {
+ final String query = "SELECT * FROM "
+ + "cp.`jsoninput/nullableOrdered1.json` t1 JOIN "
+ + "cp.`jsoninput/nullableOrdered2.json` t2 "
+ + "ON (t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)) AND t1.data LIKE '%1%'";
+ testBuilder()
+ .sqlQuery(query)
+ .unOrdered()
+ .baselineColumns("key", "data", "data0", "key0")
+ .baselineValues(null, "L_null_1", "R_null_1", null)
+ .baselineValues("A", "L_A_1", "R_A_1", "A")
+ .baselineValues(null, "L_null_1", "R_null_2", null)
+ .baselineValues(null, "L_null_1", "R_null_3", null)
+ .go();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/drill/blob/a29f1e29/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0768720..0e92098 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1446,7 +1446,7 @@
<dependency>
<groupId>org.apache.calcite</groupId>
<artifactId>calcite-core</artifactId>
- <version>1.4.0-drill-r18</version>
+ <version>1.4.0-drill-r19</version>
<exclusions>
<exclusion>
<groupId>org.jgrapht</groupId>
|