use of io.trino.sql.tree.SymbolReference in project trino by trinodb.
the class InlineProjectIntoFilter method apply.
@Override
public Result apply(FilterNode node, Captures captures, Context context) {
ProjectNode projectNode = captures.get(PROJECTION);
List<Expression> filterConjuncts = extractConjuncts(node.getPredicate());
Map<Boolean, List<Expression>> conjuncts = filterConjuncts.stream().collect(partitioningBy(SymbolReference.class::isInstance));
List<Expression> simpleConjuncts = conjuncts.get(true);
List<Expression> complexConjuncts = conjuncts.get(false);
// Do not inline expression if the symbol is used multiple times in simple conjuncts.
Set<Expression> simpleUniqueConjuncts = simpleConjuncts.stream().collect(Collectors.groupingBy(identity(), counting())).entrySet().stream().filter(entry -> entry.getValue() == 1).map(Map.Entry::getKey).collect(toImmutableSet());
Set<Expression> complexConjunctSymbols = SymbolsExtractor.extractUnique(complexConjuncts).stream().map(Symbol::toSymbolReference).collect(toImmutableSet());
// Do not inline expression if the symbol is used in complex conjuncts.
Set<Expression> simpleConjunctsToInline = Sets.difference(simpleUniqueConjuncts, complexConjunctSymbols);
if (simpleConjunctsToInline.isEmpty()) {
return Result.empty();
}
ImmutableList.Builder<Expression> newConjuncts = ImmutableList.builder();
Assignments.Builder newAssignments = Assignments.builder();
Assignments.Builder postFilterAssignmentsBuilder = Assignments.builder();
for (Expression conjunct : filterConjuncts) {
if (simpleConjunctsToInline.contains(conjunct)) {
Expression expression = projectNode.getAssignments().get(Symbol.from(conjunct));
if (expression == null || expression instanceof SymbolReference) {
// expression == null -> The symbol is not produced by the underlying projection (i.e. it is a correlation symbol).
// expression instanceof SymbolReference -> Do not inline trivial projections.
newConjuncts.add(conjunct);
} else {
newConjuncts.add(expression);
newAssignments.putIdentities(SymbolsExtractor.extractUnique(expression));
postFilterAssignmentsBuilder.put(Symbol.from(conjunct), TRUE_LITERAL);
}
} else {
newConjuncts.add(conjunct);
}
}
Assignments postFilterAssignments = postFilterAssignmentsBuilder.build();
if (postFilterAssignments.isEmpty()) {
return Result.empty();
}
Set<Symbol> postFilterSymbols = postFilterAssignments.getSymbols();
// Remove inlined expressions from the underlying projection.
newAssignments.putAll(projectNode.getAssignments().filter(symbol -> !postFilterSymbols.contains(symbol)));
Map<Symbol, Expression> outputAssignments = new HashMap<>();
outputAssignments.putAll(Assignments.identity(node.getOutputSymbols()).getMap());
// Restore inlined symbols.
outputAssignments.putAll(postFilterAssignments.getMap());
return Result.ofPlanNode(new ProjectNode(context.getIdAllocator().getNextId(), new FilterNode(node.getId(), new ProjectNode(projectNode.getId(), projectNode.getSource(), newAssignments.build()), combineConjuncts(metadata, newConjuncts.build())), Assignments.builder().putAll(outputAssignments).build()));
}
use of io.trino.sql.tree.SymbolReference in project trino by trinodb.
the class InlineProjections method extractInliningTargets.
private static Set<Symbol> extractInliningTargets(PlannerContext plannerContext, ProjectNode parent, ProjectNode child, Session session, TypeAnalyzer typeAnalyzer, TypeProvider types) {
// candidates for inlining are
// 1. references to simple constants or symbol references
// 2. references to complex expressions that
// a. are not inputs to try() expressions
// b. appear only once across all expressions
// c. are not identity projections
// which come from the child, as opposed to an enclosing scope.
Set<Symbol> childOutputSet = ImmutableSet.copyOf(child.getOutputSymbols());
Map<Symbol, Long> dependencies = parent.getAssignments().getExpressions().stream().flatMap(expression -> SymbolsExtractor.extractAll(expression).stream()).filter(childOutputSet::contains).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
// find references to simple constants or symbol references
Set<Symbol> basicReferences = dependencies.keySet().stream().filter(input -> isEffectivelyLiteral(plannerContext, session, child.getAssignments().get(input)) || child.getAssignments().get(input) instanceof SymbolReference).filter(// skip identities, otherwise, this rule will keep firing forever
input -> !child.getAssignments().isIdentity(input)).collect(toSet());
// exclude any complex inputs to TRY expressions. Inlining them would potentially
// change the semantics of those expressions
Set<Symbol> tryArguments = parent.getAssignments().getExpressions().stream().flatMap(expression -> extractTryArguments(expression).stream()).collect(toSet());
Set<Symbol> singletons = dependencies.entrySet().stream().filter(// reference appears just once across all expressions in parent project node
entry -> entry.getValue() == 1).filter(// they are not inputs to TRY. Otherwise, inlining might change semantics
entry -> !tryArguments.contains(entry.getKey())).filter(// skip identities, otherwise, this rule will keep firing forever
entry -> !child.getAssignments().isIdentity(entry.getKey())).filter(entry -> {
// skip dereferences, otherwise, inlining can cause conflicts with PushdownDereferences
Expression assignment = child.getAssignments().get(entry.getKey());
if (assignment instanceof SubscriptExpression) {
if (typeAnalyzer.getType(session, types, ((SubscriptExpression) assignment).getBase()) instanceof RowType) {
return false;
}
}
return true;
}).map(Map.Entry::getKey).collect(toSet());
return Sets.union(singletons, basicReferences);
}
use of io.trino.sql.tree.SymbolReference in project trino by trinodb.
the class EqualityInference method getScopedCanonical.
/**
* Returns a canonical expression that is fully contained by the symbolScope and that is equivalent
* to the specified expression. Returns null if unable to find a canonical.
*/
@VisibleForTesting
Expression getScopedCanonical(Expression expression, Predicate<Symbol> symbolScope) {
Expression canonicalIndex = canonicalMap.get(expression);
if (canonicalIndex == null) {
return null;
}
Collection<Expression> equivalences = equalitySets.get(canonicalIndex);
if (expression instanceof SymbolReference) {
boolean inScope = equivalences.stream().filter(SymbolReference.class::isInstance).map(Symbol::from).anyMatch(symbolScope);
if (!inScope) {
return null;
}
}
return getCanonical(equivalences.stream().filter(e -> isScoped(e, symbolScope)));
}
use of io.trino.sql.tree.SymbolReference in project trino by trinodb.
the class DomainTranslator method toPredicate.
private Expression toPredicate(Session session, Domain domain, SymbolReference reference) {
if (domain.getValues().isNone()) {
return domain.isNullAllowed() ? new IsNullPredicate(reference) : FALSE_LITERAL;
}
if (domain.getValues().isAll()) {
return domain.isNullAllowed() ? TRUE_LITERAL : new NotExpression(new IsNullPredicate(reference));
}
List<Expression> disjuncts = new ArrayList<>();
disjuncts.addAll(domain.getValues().getValuesProcessor().transform(ranges -> extractDisjuncts(session, domain.getType(), ranges, reference), discreteValues -> extractDisjuncts(session, domain.getType(), discreteValues, reference), allOrNone -> {
throw new IllegalStateException("Case should not be reachable");
}));
// Add nullability disjuncts
if (domain.isNullAllowed()) {
disjuncts.add(new IsNullPredicate(reference));
}
return combineDisjunctsWithDefault(plannerContext.getMetadata(), disjuncts, TRUE_LITERAL);
}
use of io.trino.sql.tree.SymbolReference in project trino by trinodb.
the class DynamicFilters method extractSourceSymbol.
private static Symbol extractSourceSymbol(DynamicFilters.Descriptor descriptor) {
Expression dynamicFilterExpression = descriptor.getInput();
if (dynamicFilterExpression instanceof SymbolReference) {
return Symbol.from(dynamicFilterExpression);
}
checkState(dynamicFilterExpression instanceof Cast);
checkState(((Cast) dynamicFilterExpression).getExpression() instanceof SymbolReference);
return Symbol.from(((Cast) dynamicFilterExpression).getExpression());
}
Aggregations