use of io.trino.sql.tree.SortItem in project trino by trinodb.
the class TreePrinter method print.
public void print(Node root) {
AstVisitor<Void, Integer> printer = new DefaultTraversalVisitor<Integer>() {
@Override
protected Void visitNode(Node node, Integer indentLevel) {
throw new UnsupportedOperationException("not yet implemented: " + node);
}
@Override
protected Void visitQuery(Query node, Integer indentLevel) {
print(indentLevel, "Query ");
indentLevel++;
print(indentLevel, "QueryBody");
process(node.getQueryBody(), indentLevel);
if (node.getOrderBy().isPresent()) {
print(indentLevel, "OrderBy");
process(node.getOrderBy().get(), indentLevel + 1);
}
if (node.getLimit().isPresent()) {
print(indentLevel, "Limit: " + node.getLimit().get());
}
return null;
}
@Override
protected Void visitQuerySpecification(QuerySpecification node, Integer indentLevel) {
print(indentLevel, "QuerySpecification ");
indentLevel++;
process(node.getSelect(), indentLevel);
if (node.getFrom().isPresent()) {
print(indentLevel, "From");
process(node.getFrom().get(), indentLevel + 1);
}
if (node.getWhere().isPresent()) {
print(indentLevel, "Where");
process(node.getWhere().get(), indentLevel + 1);
}
if (node.getGroupBy().isPresent()) {
String distinct = "";
if (node.getGroupBy().get().isDistinct()) {
distinct = "[DISTINCT]";
}
print(indentLevel, "GroupBy" + distinct);
for (GroupingElement groupingElement : node.getGroupBy().get().getGroupingElements()) {
print(indentLevel, "SimpleGroupBy");
if (groupingElement instanceof SimpleGroupBy) {
for (Expression column : groupingElement.getExpressions()) {
process(column, indentLevel + 1);
}
} else if (groupingElement instanceof GroupingSets) {
print(indentLevel + 1, "GroupingSets");
for (List<Expression> set : ((GroupingSets) groupingElement).getSets()) {
print(indentLevel + 2, "GroupingSet[");
for (Expression expression : set) {
process(expression, indentLevel + 3);
}
print(indentLevel + 2, "]");
}
} else if (groupingElement instanceof Cube) {
print(indentLevel + 1, "Cube");
for (Expression column : groupingElement.getExpressions()) {
process(column, indentLevel + 1);
}
} else if (groupingElement instanceof Rollup) {
print(indentLevel + 1, "Rollup");
for (Expression column : groupingElement.getExpressions()) {
process(column, indentLevel + 1);
}
}
}
}
if (node.getHaving().isPresent()) {
print(indentLevel, "Having");
process(node.getHaving().get(), indentLevel + 1);
}
if (!node.getWindows().isEmpty()) {
print(indentLevel, "Window");
for (WindowDefinition windowDefinition : node.getWindows()) {
process(windowDefinition, indentLevel + 1);
}
}
if (node.getOrderBy().isPresent()) {
print(indentLevel, "OrderBy");
process(node.getOrderBy().get(), indentLevel + 1);
}
if (node.getLimit().isPresent()) {
print(indentLevel, "Limit: " + node.getLimit().get());
}
return null;
}
@Override
protected Void visitOrderBy(OrderBy node, Integer indentLevel) {
for (SortItem sortItem : node.getSortItems()) {
process(sortItem, indentLevel);
}
return null;
}
@Override
protected Void visitWindowDefinition(WindowDefinition node, Integer indentLevel) {
print(indentLevel, "WindowDefinition[" + node.getName() + "]");
process(node.getWindow(), indentLevel + 1);
return null;
}
@Override
protected Void visitWindowReference(WindowReference node, Integer indentLevel) {
print(indentLevel, "WindowReference[" + node.getName() + "]");
return null;
}
@Override
public Void visitWindowSpecification(WindowSpecification node, Integer indentLevel) {
if (node.getExistingWindowName().isPresent()) {
print(indentLevel, "ExistingWindowName " + node.getExistingWindowName().get());
}
if (!node.getPartitionBy().isEmpty()) {
print(indentLevel, "PartitionBy");
for (Expression expression : node.getPartitionBy()) {
process(expression, indentLevel + 1);
}
}
if (node.getOrderBy().isPresent()) {
print(indentLevel, "OrderBy");
process(node.getOrderBy().get(), indentLevel + 1);
}
if (node.getFrame().isPresent()) {
print(indentLevel, "Frame");
process(node.getFrame().get(), indentLevel + 1);
}
return null;
}
@Override
protected Void visitSelect(Select node, Integer indentLevel) {
String distinct = "";
if (node.isDistinct()) {
distinct = "[DISTINCT]";
}
print(indentLevel, "Select" + distinct);
// visit children
super.visitSelect(node, indentLevel + 1);
return null;
}
@Override
protected Void visitAllColumns(AllColumns node, Integer indent) {
StringBuilder aliases = new StringBuilder();
if (!node.getAliases().isEmpty()) {
aliases.append(" [Aliases: ");
Joiner.on(", ").appendTo(aliases, node.getAliases());
aliases.append("]");
}
print(indent, "All columns" + aliases.toString());
if (node.getTarget().isPresent()) {
// visit child
super.visitAllColumns(node, indent + 1);
}
return null;
}
@Override
protected Void visitSingleColumn(SingleColumn node, Integer indent) {
if (node.getAlias().isPresent()) {
print(indent, "Alias: " + node.getAlias().get());
}
// visit children
super.visitSingleColumn(node, indent + 1);
return null;
}
@Override
protected Void visitComparisonExpression(ComparisonExpression node, Integer indentLevel) {
print(indentLevel, node.getOperator().toString());
super.visitComparisonExpression(node, indentLevel + 1);
return null;
}
@Override
protected Void visitArithmeticBinary(ArithmeticBinaryExpression node, Integer indentLevel) {
print(indentLevel, node.getOperator().toString());
super.visitArithmeticBinary(node, indentLevel + 1);
return null;
}
@Override
protected Void visitLogicalExpression(LogicalExpression node, Integer indentLevel) {
print(indentLevel, node.getOperator().toString());
super.visitLogicalExpression(node, indentLevel + 1);
return null;
}
@Override
protected Void visitStringLiteral(StringLiteral node, Integer indentLevel) {
print(indentLevel, "String[" + node.getValue() + "]");
return null;
}
@Override
protected Void visitBinaryLiteral(BinaryLiteral node, Integer indentLevel) {
print(indentLevel, "Binary[" + node.toHexString() + "]");
return null;
}
@Override
protected Void visitBooleanLiteral(BooleanLiteral node, Integer indentLevel) {
print(indentLevel, "Boolean[" + node.getValue() + "]");
return null;
}
@Override
protected Void visitLongLiteral(LongLiteral node, Integer indentLevel) {
print(indentLevel, "Long[" + node.getValue() + "]");
return null;
}
@Override
protected Void visitLikePredicate(LikePredicate node, Integer indentLevel) {
print(indentLevel, "LIKE");
super.visitLikePredicate(node, indentLevel + 1);
return null;
}
@Override
protected Void visitIdentifier(Identifier node, Integer indentLevel) {
QualifiedName resolved = resolvedNameReferences.get(node);
String resolvedName = "";
if (resolved != null) {
resolvedName = "=>" + resolved.toString();
}
print(indentLevel, "Identifier[" + node.getValue() + resolvedName + "]");
return null;
}
@Override
protected Void visitDereferenceExpression(DereferenceExpression node, Integer indentLevel) {
QualifiedName resolved = resolvedNameReferences.get(node);
String resolvedName = "";
if (resolved != null) {
resolvedName = "=>" + resolved.toString();
}
print(indentLevel, "DereferenceExpression[" + node + resolvedName + "]");
return null;
}
@Override
protected Void visitFunctionCall(FunctionCall node, Integer indentLevel) {
String name = Joiner.on('.').join(node.getName().getParts());
print(indentLevel, "FunctionCall[" + name + "]");
super.visitFunctionCall(node, indentLevel + 1);
return null;
}
@Override
protected Void visitTable(Table node, Integer indentLevel) {
String name = Joiner.on('.').join(node.getName().getParts());
print(indentLevel, "Table[" + name + "]");
return null;
}
@Override
protected Void visitValues(Values node, Integer indentLevel) {
print(indentLevel, "Values");
super.visitValues(node, indentLevel + 1);
return null;
}
@Override
protected Void visitRow(Row node, Integer indentLevel) {
print(indentLevel, "Row");
super.visitRow(node, indentLevel + 1);
return null;
}
@Override
protected Void visitAliasedRelation(AliasedRelation node, Integer indentLevel) {
print(indentLevel, "Alias[" + node.getAlias() + "]");
super.visitAliasedRelation(node, indentLevel + 1);
return null;
}
@Override
protected Void visitSampledRelation(SampledRelation node, Integer indentLevel) {
print(indentLevel, "TABLESAMPLE[" + node.getType() + " (" + node.getSamplePercentage() + ")]");
super.visitSampledRelation(node, indentLevel + 1);
return null;
}
@Override
protected Void visitTableSubquery(TableSubquery node, Integer indentLevel) {
print(indentLevel, "SubQuery");
super.visitTableSubquery(node, indentLevel + 1);
return null;
}
@Override
protected Void visitInPredicate(InPredicate node, Integer indentLevel) {
print(indentLevel, "IN");
super.visitInPredicate(node, indentLevel + 1);
return null;
}
@Override
protected Void visitSubqueryExpression(SubqueryExpression node, Integer indentLevel) {
print(indentLevel, "SubQuery");
super.visitSubqueryExpression(node, indentLevel + 1);
return null;
}
};
printer.process(root, 0);
}
use of io.trino.sql.tree.SortItem in project trino by trinodb.
the class QueryPlanner method orderingScheme.
private Optional<OrderingScheme> orderingScheme(PlanBuilder subPlan, Optional<OrderBy> orderBy, List<Expression> orderByExpressions) {
if (orderBy.isEmpty() || (isSkipRedundantSort(session)) && analysis.isOrderByRedundant(orderBy.get())) {
return Optional.empty();
}
Iterator<SortItem> sortItems = orderBy.get().getSortItems().iterator();
ImmutableList.Builder<Symbol> orderBySymbols = ImmutableList.builder();
Map<Symbol, SortOrder> orderings = new HashMap<>();
for (Expression fieldOrExpression : orderByExpressions) {
Symbol symbol = subPlan.translate(fieldOrExpression);
SortItem sortItem = sortItems.next();
if (!orderings.containsKey(symbol)) {
orderBySymbols.add(symbol);
orderings.put(symbol, sortItemToSortOrder(sortItem));
}
}
return Optional.of(new OrderingScheme(orderBySymbols.build(), orderings));
}
use of io.trino.sql.tree.SortItem in project trino by trinodb.
the class RelationPlanner method visitPatternRecognitionRelation.
@Override
protected RelationPlan visitPatternRecognitionRelation(PatternRecognitionRelation node, Void context) {
RelationPlan subPlan = process(node.getInput(), context);
// Pre-project inputs for PARTITION BY and ORDER BY
List<Expression> inputs = ImmutableList.<Expression>builder().addAll(node.getPartitionBy()).addAll(getSortItemsFromOrderBy(node.getOrderBy()).stream().map(SortItem::getSortKey).collect(toImmutableList())).build();
PlanBuilder planBuilder = newPlanBuilder(subPlan, analysis, lambdaDeclarationToSymbolMap);
// no handleSubqueries because subqueries are not allowed here
planBuilder = planBuilder.appendProjections(inputs, symbolAllocator, idAllocator);
ImmutableList.Builder<Symbol> outputLayout = ImmutableList.builder();
boolean oneRowOutput = node.getRowsPerMatch().isEmpty() || node.getRowsPerMatch().get().isOneRow();
WindowNode.Specification specification = planWindowSpecification(node.getPartitionBy(), node.getOrderBy(), planBuilder::translate);
outputLayout.addAll(specification.getPartitionBy());
if (!oneRowOutput) {
getSortItemsFromOrderBy(node.getOrderBy()).stream().map(SortItem::getSortKey).map(planBuilder::translate).forEach(outputLayout::add);
}
planBuilder = subqueryPlanner.handleSubqueries(planBuilder, extractPatternRecognitionExpressions(node.getVariableDefinitions(), node.getMeasures()), analysis.getSubqueries(node));
PatternRecognitionComponents components = planPatternRecognitionComponents(planBuilder::rewrite, node.getSubsets(), node.getMeasures(), node.getAfterMatchSkipTo(), node.getPatternSearchMode(), node.getPattern(), node.getVariableDefinitions());
outputLayout.addAll(components.getMeasureOutputs());
if (!oneRowOutput) {
Set<Symbol> inputSymbolsOnOutput = ImmutableSet.copyOf(outputLayout.build());
subPlan.getFieldMappings().stream().filter(symbol -> !inputSymbolsOnOutput.contains(symbol)).forEach(outputLayout::add);
}
PatternRecognitionNode planNode = new PatternRecognitionNode(idAllocator.getNextId(), planBuilder.getRoot(), specification, Optional.empty(), ImmutableSet.of(), 0, ImmutableMap.of(), components.getMeasures(), Optional.empty(), node.getRowsPerMatch().orElse(ONE), components.getSkipToLabel(), components.getSkipToPosition(), components.isInitial(), components.getPattern(), components.getSubsets(), components.getVariableDefinitions());
return new RelationPlan(planNode, analysis.getScope(node), outputLayout.build(), outerContext);
}
use of io.trino.sql.tree.SortItem in project trino by trinodb.
the class QueryPlanner method aggregate.
private PlanBuilder aggregate(PlanBuilder subPlan, QuerySpecification node) {
if (!analysis.isAggregation(node)) {
return subPlan;
}
ImmutableList.Builder<Expression> inputBuilder = ImmutableList.builder();
analysis.getAggregates(node).stream().map(FunctionCall::getArguments).flatMap(List::stream).filter(// lambda expression is generated at execution time
expression -> !(expression instanceof LambdaExpression)).forEach(inputBuilder::add);
analysis.getAggregates(node).stream().map(FunctionCall::getOrderBy).map(NodeUtils::getSortItemsFromOrderBy).flatMap(List::stream).map(SortItem::getSortKey).forEach(inputBuilder::add);
// filter expressions need to be projected first
analysis.getAggregates(node).stream().map(FunctionCall::getFilter).filter(Optional::isPresent).map(Optional::get).forEach(inputBuilder::add);
GroupingSetAnalysis groupingSetAnalysis = analysis.getGroupingSets(node);
inputBuilder.addAll(groupingSetAnalysis.getComplexExpressions());
List<Expression> inputs = inputBuilder.build();
subPlan = subqueryPlanner.handleSubqueries(subPlan, inputs, analysis.getSubqueries(node));
subPlan = subPlan.appendProjections(inputs, symbolAllocator, idAllocator);
// Add projection to coerce inputs to their site-specific types.
// This is important because the same lexical expression may need to be coerced
// in different ways if it's referenced by multiple arguments to the window function.
// For example, given v::integer,
// avg(v)
// Needs to be rewritten as
// avg(CAST(v AS double))
PlanAndMappings coercions = coerce(subPlan, inputs, analysis, idAllocator, symbolAllocator, typeCoercion);
subPlan = coercions.getSubPlan();
GroupingSetsPlan groupingSets = planGroupingSets(subPlan, node, groupingSetAnalysis);
subPlan = planAggregation(groupingSets.getSubPlan(), groupingSets.getGroupingSets(), groupingSets.getGroupIdSymbol(), analysis.getAggregates(node), coercions::get);
return planGroupingOperations(subPlan, node, groupingSets.getGroupIdSymbol(), groupingSets.getColumnOnlyGroupingSets());
}
use of io.trino.sql.tree.SortItem in project trino by trinodb.
the class QueryPlanner method planWindowFunctions.
private PlanBuilder planWindowFunctions(Node node, PlanBuilder subPlan, List<FunctionCall> windowFunctions) {
if (windowFunctions.isEmpty()) {
return subPlan;
}
for (FunctionCall windowFunction : scopeAwareDistinct(subPlan, windowFunctions)) {
checkArgument(windowFunction.getFilter().isEmpty(), "Window functions cannot have filter");
ResolvedWindow window = analysis.getWindow(windowFunction);
checkState(window != null, "no resolved window for: " + windowFunction);
// Pre-project inputs.
// Predefined window parts (specified in WINDOW clause) can only use source symbols, and no output symbols.
// It matters in case when this window planning takes place in ORDER BY clause, where both source and output
// symbols are visible.
// This issue is solved by analyzing window definitions in the source scope. After analysis, the expressions
// are recorded as belonging to the source scope, and consequentially source symbols will be used to plan them.
ImmutableList.Builder<Expression> inputsBuilder = ImmutableList.<Expression>builder().addAll(windowFunction.getArguments().stream().filter(// lambda expression is generated at execution time
argument -> !(argument instanceof LambdaExpression)).collect(Collectors.toList())).addAll(window.getPartitionBy()).addAll(getSortItemsFromOrderBy(window.getOrderBy()).stream().map(SortItem::getSortKey).iterator());
if (window.getFrame().isPresent()) {
WindowFrame frame = window.getFrame().get();
frame.getStart().getValue().ifPresent(inputsBuilder::add);
if (frame.getEnd().isPresent()) {
frame.getEnd().get().getValue().ifPresent(inputsBuilder::add);
}
}
List<Expression> inputs = inputsBuilder.build();
subPlan = subqueryPlanner.handleSubqueries(subPlan, inputs, analysis.getSubqueries(node));
subPlan = subPlan.appendProjections(inputs, symbolAllocator, idAllocator);
// Add projection to coerce inputs to their site-specific types.
// This is important because the same lexical expression may need to be coerced
// in different ways if it's referenced by multiple arguments to the window function.
// For example, given v::integer,
// avg(v) OVER (ORDER BY v)
// Needs to be rewritten as
// avg(CAST(v AS double)) OVER (ORDER BY v)
PlanAndMappings coercions = coerce(subPlan, inputs, analysis, idAllocator, symbolAllocator, typeCoercion);
subPlan = coercions.getSubPlan();
// For frame of type RANGE, append casts and functions necessary for frame bound calculations
Optional<Symbol> frameStart = Optional.empty();
Optional<Symbol> frameEnd = Optional.empty();
Optional<Symbol> sortKeyCoercedForFrameStartComparison = Optional.empty();
Optional<Symbol> sortKeyCoercedForFrameEndComparison = Optional.empty();
if (window.getFrame().isPresent() && window.getFrame().get().getType() == RANGE) {
Optional<Expression> startValue = window.getFrame().get().getStart().getValue();
Optional<Expression> endValue = window.getFrame().get().getEnd().flatMap(FrameBound::getValue);
// record sortKey coercions for reuse
Map<Type, Symbol> sortKeyCoercions = new HashMap<>();
// process frame start
FrameBoundPlanAndSymbols plan = planFrameBound(subPlan, coercions, startValue, window, sortKeyCoercions);
subPlan = plan.getSubPlan();
frameStart = plan.getFrameBoundSymbol();
sortKeyCoercedForFrameStartComparison = plan.getSortKeyCoercedForFrameBoundComparison();
// process frame end
plan = planFrameBound(subPlan, coercions, endValue, window, sortKeyCoercions);
subPlan = plan.getSubPlan();
frameEnd = plan.getFrameBoundSymbol();
sortKeyCoercedForFrameEndComparison = plan.getSortKeyCoercedForFrameBoundComparison();
} else if (window.getFrame().isPresent() && (window.getFrame().get().getType() == ROWS || window.getFrame().get().getType() == GROUPS)) {
Optional<Expression> startValue = window.getFrame().get().getStart().getValue();
Optional<Expression> endValue = window.getFrame().get().getEnd().flatMap(FrameBound::getValue);
// process frame start
FrameOffsetPlanAndSymbol plan = planFrameOffset(subPlan, startValue.map(coercions::get));
subPlan = plan.getSubPlan();
frameStart = plan.getFrameOffsetSymbol();
// process frame end
plan = planFrameOffset(subPlan, endValue.map(coercions::get));
subPlan = plan.getSubPlan();
frameEnd = plan.getFrameOffsetSymbol();
} else if (window.getFrame().isPresent()) {
throw new IllegalArgumentException("unexpected window frame type: " + window.getFrame().get().getType());
}
if (window.getFrame().isPresent() && window.getFrame().get().getPattern().isPresent()) {
WindowFrame frame = window.getFrame().get();
subPlan = subqueryPlanner.handleSubqueries(subPlan, extractPatternRecognitionExpressions(frame.getVariableDefinitions(), frame.getMeasures()), analysis.getSubqueries(node));
subPlan = planPatternRecognition(subPlan, windowFunction, window, coercions, frameEnd);
} else {
subPlan = planWindow(subPlan, windowFunction, window, coercions, frameStart, sortKeyCoercedForFrameStartComparison, frameEnd, sortKeyCoercedForFrameEndComparison);
}
}
return subPlan;
}
Aggregations