use of io.crate.planner.node.dql.join.JoinType in project crate by crate.
the class Rewriter method tryRewriteOuterToInnerJoin.
/**
* Rewrite an Outer join to an inner join if possible.
* <p>
* Conditions on OUTER tables are not pushed down when a MultiSourceSelect is initially created because
* the whereClause needs to be checked AFTER the join
* (because if the join generates NULL rows the whereClause could become TRUE on those NULL rows)
* <p>
* See the following two examples where <code>t2</code> is the OUTER table:
* <p>
* <pre>
* select * from t1
* left join t2 on t1.t2_id = t2.id
* where
* coalesce(t2.x, 20) > 10 # becomes TRUE for null rows
* </pre>
* <p>
* <p>
* <p>
* But if we know that the whereClause cannot possible become TRUE then we can push it down
* (re-writing this into an inner join)
* <p>
* This is possible because all rows that are generated by the left-join would be removed again by the whereClause anyway.
* <p>
* <pre>
* select * from t1
* left join t2 on t1.t2_id = t2.id
* where
* t2.x > 10 # if t2.x is NULL this is always FALSE
* </pre>
*/
public static void tryRewriteOuterToInnerJoin(EvaluatingNormalizer normalizer, JoinPair joinPair, List<Symbol> mssOutputSymbols, QuerySpec multiSourceQuerySpec, QualifiedName left, QualifiedName right, QuerySpec leftQuerySpec, QuerySpec rightQuerySpec) {
assert left.equals(joinPair.left()) : "This JoinPair has a different left Qualified name: " + joinPair.left();
assert right.equals(joinPair.right()) : "This JoinPair has a different left Qualified name: " + joinPair.right();
JoinType joinType = joinPair.joinType();
if (!joinType.isOuter()) {
return;
}
WhereClause where = multiSourceQuerySpec.where();
if (!where.hasQuery()) {
return;
}
final Map<QualifiedName, QuerySpec> outerRelations = new HashMap<>(2);
switch(joinType) {
case LEFT:
outerRelations.put(right, rightQuerySpec);
break;
case RIGHT:
outerRelations.put(left, leftQuerySpec);
break;
case FULL:
outerRelations.put(left, leftQuerySpec);
outerRelations.put(right, rightQuerySpec);
break;
}
Map<Set<QualifiedName>, Symbol> splitQueries = QuerySplitter.split(where.query());
for (QualifiedName outerRelation : outerRelations.keySet()) {
Symbol outerRelationQuery = splitQueries.remove(Sets.newHashSet(outerRelation));
if (outerRelationQuery != null) {
QuerySpec outerSpec = outerRelations.get(outerRelation);
Symbol symbol = Symbols.replaceField(outerRelationQuery, new Function<Field, Symbol>() {
@Nullable
@Override
public Symbol apply(@Nullable Field input) {
if (input != null && input.relation().getQualifiedName().equals(outerRelation)) {
return Literal.NULL;
}
return input;
}
});
Symbol normalized = normalizer.normalize(symbol, null);
if (WhereClause.canMatch(normalized)) {
splitQueries.put(Sets.newHashSet(outerRelation), outerRelationQuery);
} else {
applyOuterJoinRewrite(joinPair, mssOutputSymbols, multiSourceQuerySpec, outerSpec, outerRelation, splitQueries, outerRelationQuery);
}
}
}
}
Aggregations