public static Expression replaceExpression(Expression expression, Map<? extends Expression, ? extends Expression> mappings) { return ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(mappings), expression); }
private Optional<Expression> removeExpressionFromFilter(Expression filter, Expression expression) { Expression updatedJoinFilter = replaceExpression(filter, ImmutableMap.of(expression, TRUE_LITERAL)); return updatedJoinFilter == TRUE_LITERAL ? Optional.empty() : Optional.of(updatedJoinFilter); }
/** * Performs one pass of generating more equivalences by rewriting sub-expressions in terms of known equivalences. */ private void generateMoreEquivalences() { Collection<Set<Expression>> equivalentClasses = equalities.getEquivalentClasses(); // Map every expression to the set of equivalent expressions ImmutableMap.Builder<Expression, Set<Expression>> mapBuilder = ImmutableMap.builder(); for (Set<Expression> expressions : equivalentClasses) { expressions.forEach(expression -> mapBuilder.put(expression, expressions)); } // For every non-derived expression, extract the sub-expressions and see if they can be rewritten as other expressions. If so, // use this new information to update the known equalities. Map<Expression, Set<Expression>> map = mapBuilder.build(); for (Expression expression : map.keySet()) { if (!derivedExpressions.contains(expression)) { for (Expression subExpression : filter(SubExpressionExtractor.extract(expression), not(equalTo(expression)))) { Set<Expression> equivalentSubExpressions = map.get(subExpression); if (equivalentSubExpressions != null) { for (Expression equivalentSubExpression : filter(equivalentSubExpressions, not(equalTo(subExpression)))) { Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(ImmutableMap.of(subExpression, equivalentSubExpression)), expression); equalities.findAndUnion(expression, rewritten); derivedExpressions.add(rewritten); } } } } } }
@Override public PlanNode visitValues(ValuesNode node, RewriteContext<Void> context) { ValuesNode rewrittenNode = (ValuesNode) context.defaultRewrite(node); List<List<Expression>> rewrittenRows = rewrittenNode.getRows().stream() .map(row -> row.stream() .map(column -> replaceExpression(column, mapping)) .collect(toImmutableList())) .collect(toImmutableList()); return new ValuesNode( idAllocator.getNextId(), rewrittenNode.getOutputSymbols(), rewrittenRows); } }
private Expression rewriteExpression(Expression expression, Predicate<Symbol> symbolScope, boolean allowFullReplacement) { Iterable<Expression> subExpressions = SubExpressionExtractor.extract(expression); if (!allowFullReplacement) { subExpressions = filter(subExpressions, not(equalTo(expression))); } ImmutableMap.Builder<Expression, Expression> expressionRemap = ImmutableMap.builder(); for (Expression subExpression : subExpressions) { Expression canonical = getScopedCanonical(subExpression, symbolScope); if (canonical != null) { expressionRemap.put(subExpression, canonical); } } // Perform a naive single-pass traversal to try to rewrite non-compliant portions of the tree. Prefers to replace // larger subtrees over smaller subtrees // TODO: this rewrite can probably be made more sophisticated Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(expressionRemap.build()), expression); if (!symbolToExpressionPredicate(symbolScope).apply(rewritten)) { // If the rewritten is still not compliant with the symbol scope, just give up return null; } return rewritten; }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { FilterNode rewrittenNode = (FilterNode) context.defaultRewrite(node); return new FilterNode(idAllocator.getNextId(), rewrittenNode.getSource(), replaceExpression(rewrittenNode.getPredicate(), mapping)); }
private Expression normalize(Expression expression) { Expression identityNormalizedExpression = expressionCache.get(expression); if (identityNormalizedExpression == null) { // Make sure all sub-expressions are normalized first for (Expression subExpression : Iterables.filter(SubExpressionExtractor.extract(expression), Predicates.not(Predicates.equalTo(expression)))) { normalize(subExpression); } // Since we have not seen this expression before, rewrite it entirely in terms of the normalized sub-expressions identityNormalizedExpression = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(expressionCache), expression); expressionCache.put(identityNormalizedExpression, identityNormalizedExpression); } return identityNormalizedExpression; } }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Void> context) { ProjectNode rewrittenNode = (ProjectNode) context.defaultRewrite(node); Assignments assignments = rewrittenNode.getAssignments() .rewrite(expression -> replaceExpression(expression, mapping)); return new ProjectNode(idAllocator.getNextId(), rewrittenNode.getSource(), assignments); }
/** * Performs one pass of generating more equivalences by rewriting sub-expressions in terms of known equivalences. */ private void generateMoreEquivalences() { Collection<Set<Expression>> equivalentClasses = equalities.getEquivalentClasses(); // Map every expression to the set of equivalent expressions Map<Expression, Set<Expression>> map = new HashMap<>(); for (Set<Expression> expressions : equivalentClasses) { expressions.stream().forEach(expression -> map.put(expression, expressions)); } // For every non-derived expression, extract the sub-expressions and see if they can be rewritten as other expressions. If so, // use this new information to update the known equalities. for (Expression expression : map.keySet()) { if (!derivedExpressions.contains(expression)) { for (Expression subExpression : filter(SubExpressionExtractor.extract(expression), not(equalTo(expression)))) { Set<Expression> equivalentSubExpressions = map.get(subExpression); if (equivalentSubExpressions != null) { for (Expression equivalentSubExpression : filter(equivalentSubExpressions, not(equalTo(subExpression)))) { Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(ImmutableMap.of(subExpression, equivalentSubExpression)), expression); equalities.findAndUnion(expression, rewritten); derivedExpressions.add(rewritten); } } } } } }
@VisibleForTesting public static final class ExtractSpatialLeftJoin implements Rule<JoinNode> { private static final Pattern<JoinNode> PATTERN = join().matching(node -> node.getCriteria().isEmpty() && node.getFilter().isPresent() && node.getType() == LEFT); private final Metadata metadata; private final SplitManager splitManager; private final PageSourceManager pageSourceManager; private final SqlParser sqlParser; public ExtractSpatialLeftJoin(Metadata metadata, SplitManager splitManager, PageSourceManager pageSourceManager, SqlParser sqlParser) { this.metadata = requireNonNull(metadata, "metadata is null"); this.splitManager = requireNonNull(splitManager, "splitManager is null"); this.pageSourceManager = requireNonNull(pageSourceManager, "pageSourceManager is null"); this.sqlParser = requireNonNull(sqlParser, "sqlParser is null"); } @Override public boolean isEnabled(Session session) { return isSpatialJoinEnabled(session); } @Override public Pattern<JoinNode> getPattern() { return PATTERN; }
private Expression rewriteExpression(Expression expression, Predicate<Symbol> symbolScope, boolean allowFullReplacement) { Iterable<Expression> subExpressions = SubExpressionExtractor.extract(expression); if (!allowFullReplacement) { subExpressions = filter(subExpressions, not(equalTo(expression))); } ImmutableMap.Builder<Expression, Expression> expressionRemap = ImmutableMap.builder(); for (Expression subExpression : subExpressions) { Expression canonical = getScopedCanonical(subExpression, symbolScope); if (canonical != null) { expressionRemap.put(subExpression, canonical); } } // Perform a naive single-pass traversal to try to rewrite non-compliant portions of the tree. Prefers to replace // larger subtrees over smaller subtrees // TODO: this rewrite can probably be made more sophisticated Expression rewritten = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(expressionRemap.build()), expression); if (!symbolToExpressionPredicate(symbolScope).apply(rewritten)) { // If the rewritten is still not compliant with the symbol scope, just give up return null; } return rewritten; }
private Expression normalize(Expression expression) { Expression identityNormalizedExpression = expressionCache.get(expression); if (identityNormalizedExpression == null) { // Make sure all sub-expressions are normalized first for (Expression subExpression : Iterables.filter(SubExpressionExtractor.extract(expression), Predicates.not(Predicates.equalTo(expression)))) { normalize(subExpression); } // Since we have not seen this expression before, rewrite it entirely in terms of the normalized sub-expressions identityNormalizedExpression = ExpressionTreeRewriter.rewriteWith(new ExpressionNodeInliner(expressionCache), expression); expressionCache.put(identityNormalizedExpression, identityNormalizedExpression); } return identityNormalizedExpression; } }