use of io.crate.metadata.RelationName in project crate by crate.
the class JoinPlanBuilder method joinWithNext.
private static LogicalPlan joinWithNext(Function<AnalyzedRelation, LogicalPlan> plan, LogicalPlan source, AnalyzedRelation nextRel, Set<RelationName> joinNames, Map<Set<RelationName>, JoinPair> joinPairs, Map<Set<RelationName>, Symbol> queryParts, AnalyzedRelation leftRelation, boolean hashJoinEnabled) {
RelationName nextName = nextRel.relationName();
JoinPair joinPair = removeMatch(joinPairs, joinNames, nextName);
final JoinType type;
final Symbol condition;
if (joinPair == null) {
type = JoinType.CROSS;
condition = null;
} else {
type = maybeInvertPair(nextName, joinPair);
condition = joinPair.condition();
}
LogicalPlan nextPlan = plan.apply(nextRel);
Symbol query = AndOperator.join(Stream.of(removeMatch(queryParts, joinNames, nextName), queryParts.remove(Collections.singleton(nextName))).filter(Objects::nonNull).iterator());
return Filter.create(createJoinPlan(source, nextPlan, type, condition, leftRelation, nextRel, query, hashJoinEnabled), query);
}
use of io.crate.metadata.RelationName in project crate by crate.
the class JoinPlanBuilder method buildJoinTree.
static LogicalPlan buildJoinTree(List<AnalyzedRelation> from, Symbol whereClause, List<JoinPair> joinPairs, Function<AnalyzedRelation, LogicalPlan> plan, boolean hashJoinEnabled) {
if (from.size() == 1) {
return Filter.create(plan.apply(from.get(0)), whereClause);
}
Map<Set<RelationName>, Symbol> queryParts = QuerySplitter.split(whereClause);
List<JoinPair> allJoinPairs = JoinOperations.convertImplicitJoinConditionsToJoinPairs(joinPairs, queryParts);
boolean optimizeOrder = true;
for (var joinPair : allJoinPairs) {
if (hasAdditionalDependencies(joinPair)) {
optimizeOrder = false;
break;
}
}
LinkedHashMap<Set<RelationName>, JoinPair> joinPairsByRelations = JoinOperations.buildRelationsToJoinPairsMap(allJoinPairs);
Iterator<RelationName> it;
if (optimizeOrder) {
Collection<RelationName> orderedRelationNames = JoinOrdering.getOrderedRelationNames(Lists2.map(from, AnalyzedRelation::relationName), joinPairsByRelations.keySet(), queryParts.keySet());
it = orderedRelationNames.iterator();
} else {
it = Lists2.map(from, AnalyzedRelation::relationName).iterator();
}
final RelationName lhsName = it.next();
final RelationName rhsName = it.next();
Set<RelationName> joinNames = new HashSet<>();
joinNames.add(lhsName);
joinNames.add(rhsName);
JoinPair joinLhsRhs = joinPairsByRelations.remove(joinNames);
final JoinType joinType;
final Symbol joinCondition;
if (joinLhsRhs == null) {
joinType = JoinType.CROSS;
joinCondition = null;
} else {
joinType = maybeInvertPair(rhsName, joinLhsRhs);
joinCondition = joinLhsRhs.condition();
}
Map<RelationName, AnalyzedRelation> sources = from.stream().collect(Collectors.toMap(AnalyzedRelation::relationName, rel -> rel));
AnalyzedRelation lhs = sources.get(lhsName);
AnalyzedRelation rhs = sources.get(rhsName);
LogicalPlan lhsPlan = plan.apply(lhs);
LogicalPlan rhsPlan = plan.apply(rhs);
Symbol query = removeParts(queryParts, lhsName, rhsName);
LogicalPlan joinPlan = createJoinPlan(lhsPlan, rhsPlan, joinType, joinCondition, lhs, rhs, query, hashJoinEnabled);
joinPlan = Filter.create(joinPlan, query);
while (it.hasNext()) {
AnalyzedRelation nextRel = sources.get(it.next());
joinPlan = joinWithNext(plan, joinPlan, nextRel, joinNames, joinPairsByRelations, queryParts, lhs, hashJoinEnabled);
joinNames.add(nextRel.relationName());
}
if (!queryParts.isEmpty()) {
joinPlan = Filter.create(joinPlan, AndOperator.join(queryParts.values()));
queryParts.clear();
}
assert joinPairsByRelations.isEmpty() : "Must've applied all joinPairs";
return joinPlan;
}
use of io.crate.metadata.RelationName in project crate by crate.
the class SysTableRegistry method registerSysTable.
public <R> void registerSysTable(TableInfo tableInfo, Supplier<CompletableFuture<? extends Iterable<R>>> iterableSupplier, Map<ColumnIdent, ? extends RowCollectExpressionFactory<R>> expressionFactories, boolean involvesIO) {
RelationName ident = tableInfo.ident();
sysSchemaInfo.registerSysTable(tableInfo);
tableDefinitions.registerTableDefinition(ident, new StaticTableDefinition<>(iterableSupplier, expressionFactories, involvesIO));
}
use of io.crate.metadata.RelationName in project crate by crate.
the class RewriteFilterOnOuterJoinToInnerJoin method apply.
@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
var symbolEvaluator = new SymbolEvaluator(txnCtx, nodeCtx, SubQueryResults.EMPTY);
NestedLoopJoin nl = captures.get(nlCapture);
Symbol query = filter.query();
Map<Set<RelationName>, Symbol> splitQueries = QuerySplitter.split(query);
if (splitQueries.size() == 1 && splitQueries.keySet().iterator().next().size() > 1) {
return null;
}
LogicalPlan lhs = nl.sources().get(0);
LogicalPlan rhs = nl.sources().get(1);
Set<RelationName> leftName = lhs.getRelationNames();
Set<RelationName> rightName = rhs.getRelationNames();
Symbol leftQuery = splitQueries.remove(leftName);
Symbol rightQuery = splitQueries.remove(rightName);
final LogicalPlan newLhs;
final LogicalPlan newRhs;
final boolean newJoinIsInnerJoin;
switch(nl.joinType()) {
case LEFT:
/* LEFT OUTER JOIN -> NULL rows are generated for the RHS if the join-condition doesn't match
*
* cr> select t1.x as t1x, t2.x as t2x from t1 left join t2 on t1.x = t2.x;
* +-----+------+
* | t1x | t2x |
* +-----+------+
* | 3 | 3 |
* | 2 | 2 |
* | 1 | NULL |
* +-----+------+
*/
newLhs = getNewSource(leftQuery, lhs);
if (rightQuery == null) {
newRhs = rhs;
newJoinIsInnerJoin = false;
} else if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
newRhs = rhs;
newJoinIsInnerJoin = false;
splitQueries.put(rightName, rightQuery);
} else {
newRhs = getNewSource(rightQuery, rhs);
newJoinIsInnerJoin = true;
}
break;
case RIGHT:
/* RIGHT OUTER JOIN -> NULL rows are generated for the LHS if the join-condition doesn't match
* cr> select t1.x as t1x, t2.x as t2x from t1 right join t2 on t1.x = t2.x;
* +------+-----+
* | t1x | t2x |
* +------+-----+
* | 3 | 3 |
* | 2 | 2 |
* | NULL | 4 |
* +------+-----+
*/
if (leftQuery == null) {
newLhs = lhs;
newJoinIsInnerJoin = false;
} else if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
newLhs = lhs;
newJoinIsInnerJoin = false;
splitQueries.put(leftName, leftQuery);
} else {
newLhs = getNewSource(leftQuery, lhs);
newJoinIsInnerJoin = true;
}
newRhs = getNewSource(rightQuery, rhs);
break;
case FULL:
if (couldMatchOnNull(leftQuery, symbolEvaluator)) {
newLhs = lhs;
} else {
newLhs = getNewSource(leftQuery, lhs);
if (leftQuery != null) {
splitQueries.put(leftName, leftQuery);
}
}
if (couldMatchOnNull(rightQuery, symbolEvaluator)) {
newRhs = rhs;
} else {
newRhs = getNewSource(rightQuery, rhs);
}
/*
* Filters on each side must be put back into the Filter as each side can generate NULL's on outer joins
* which must be filtered out AFTER the join operation.
* In case the filter is only on one side, the join could be rewritten to a LEFT/RIGHT OUTER.
* TODO: Create a dedicated rule RewriteFilterOnOuterJoinToLeftOrRight
*
* cr> select t1.x as t1x, t2.x as t2x, t2.y as t2y from t1 full outer join t2 on t1.x = t2.x where t2y = 1;
* +------+------+------+
* | t1x | t2x | t2y |
* +------+------+------+
* | 3 | 3 | 1 |
* | 2 | 2 | 1 |
* | NULL | 4 | 1 |
* +------+------+------+
*/
if (leftQuery != null) {
splitQueries.put(leftName, leftQuery);
}
if (rightQuery != null) {
splitQueries.put(rightName, rightQuery);
}
newJoinIsInnerJoin = newLhs != lhs && newRhs != rhs;
break;
default:
throw new UnsupportedOperationException("The Rule to rewrite filter+outer-joins to inner joins must not be run on joins of type=" + nl.joinType());
}
if (newLhs == lhs && newRhs == rhs) {
return null;
}
NestedLoopJoin newJoin = new NestedLoopJoin(newLhs, newRhs, newJoinIsInnerJoin ? JoinType.INNER : nl.joinType(), nl.joinCondition(), nl.isFiltered(), nl.topMostLeftRelation(), nl.orderByWasPushedDown(), true);
assert newJoin.outputs().equals(nl.outputs()) : "Outputs after rewrite must be the same as before";
return splitQueries.isEmpty() ? newJoin : new Filter(newJoin, AndOperator.join(splitQueries.values()));
}
use of io.crate.metadata.RelationName in project crate by crate.
the class RewriteToQueryThenFetch method apply.
@Override
public LogicalPlan apply(Limit limit, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
if (Symbols.containsColumn(limit.outputs(), DocSysColumns.FETCHID)) {
return null;
}
FetchRewrite fetchRewrite = limit.source().rewriteToFetch(tableStats, Set.of());
if (fetchRewrite == null) {
return null;
}
List<Reference> fetchRefs = fetchRewrite.extractFetchRefs();
Map<RelationName, FetchSource> fetchSourceByRelation = fetchRewrite.createFetchSources();
return new Fetch(fetchRewrite.replacedOutputs(), fetchRefs, fetchSourceByRelation, limit.replaceSources(List.of(fetchRewrite.newPlan())));
}
Aggregations