use of com.facebook.presto.spi.relation.CallExpression in project presto by prestodb.
the class QueryPlanner method window.
private PlanBuilder window(PlanBuilder subPlan, List<FunctionCall> windowFunctions) {
if (windowFunctions.isEmpty()) {
return subPlan;
}
for (FunctionCall windowFunction : windowFunctions) {
Window window = windowFunction.getWindow().get();
// Extract frame
WindowFrame.Type frameType = WindowFrame.Type.RANGE;
FrameBound.Type frameStartType = FrameBound.Type.UNBOUNDED_PRECEDING;
FrameBound.Type frameEndType = FrameBound.Type.CURRENT_ROW;
Expression frameStart = null;
Expression frameEnd = null;
if (window.getFrame().isPresent()) {
WindowFrame frame = window.getFrame().get();
frameType = frame.getType();
frameStartType = frame.getStart().getType();
frameStart = frame.getStart().getValue().orElse(null);
if (frame.getEnd().isPresent()) {
frameEndType = frame.getEnd().get().getType();
frameEnd = frame.getEnd().get().getValue().orElse(null);
}
}
// Pre-project inputs
ImmutableList.Builder<Expression> inputs = ImmutableList.<Expression>builder().addAll(windowFunction.getArguments()).addAll(window.getPartitionBy()).addAll(Iterables.transform(getSortItemsFromOrderBy(window.getOrderBy()), SortItem::getSortKey));
if (frameStart != null) {
inputs.add(frameStart);
}
if (frameEnd != null) {
inputs.add(frameEnd);
}
subPlan = subPlan.appendProjections(inputs.build(), variableAllocator, idAllocator);
// Rewrite PARTITION BY in terms of pre-projected inputs
ImmutableList.Builder<VariableReferenceExpression> partitionByVariables = ImmutableList.builder();
for (Expression expression : window.getPartitionBy()) {
partitionByVariables.add(subPlan.translateToVariable(expression));
}
// Rewrite ORDER BY in terms of pre-projected inputs
LinkedHashMap<VariableReferenceExpression, SortOrder> orderings = new LinkedHashMap<>();
for (SortItem item : getSortItemsFromOrderBy(window.getOrderBy())) {
VariableReferenceExpression variable = subPlan.translateToVariable(item.getSortKey());
// don't override existing keys, i.e. when "ORDER BY a ASC, a DESC" is specified
orderings.putIfAbsent(variable, toSortOrder(item));
}
// Rewrite frame bounds in terms of pre-projected inputs
Optional<VariableReferenceExpression> frameStartVariable = Optional.empty();
Optional<VariableReferenceExpression> frameEndVariable = Optional.empty();
if (frameStart != null) {
frameStartVariable = Optional.of(subPlan.translate(frameStart));
}
if (frameEnd != null) {
frameEndVariable = Optional.of(subPlan.translate(frameEnd));
}
WindowNode.Frame frame = new WindowNode.Frame(toWindowType(frameType), toBoundType(frameStartType), frameStartVariable, toBoundType(frameEndType), frameEndVariable, Optional.ofNullable(frameStart).map(Expression::toString), Optional.ofNullable(frameEnd).map(Expression::toString));
TranslationMap outputTranslations = subPlan.copyTranslations();
// Rewrite function call in terms of pre-projected inputs
Expression rewritten = subPlan.rewrite(windowFunction);
boolean needCoercion = rewritten instanceof Cast;
// Strip out the cast and add it back as a post-projection
if (rewritten instanceof Cast) {
rewritten = ((Cast) rewritten).getExpression();
}
// If refers to existing variable, don't create another PlanNode
if (rewritten instanceof SymbolReference) {
if (needCoercion) {
subPlan = explicitCoercionVariables(subPlan, subPlan.getRoot().getOutputVariables(), ImmutableList.of(windowFunction));
}
continue;
}
Type returnType = analysis.getType(windowFunction);
VariableReferenceExpression newVariable = variableAllocator.newVariable(rewritten, returnType);
outputTranslations.put(windowFunction, newVariable);
// TODO: replace arguments with RowExpression once we introduce subquery expression for RowExpression (#12745).
// Wrap all arguments in CallExpression to be RawExpression.
// The utility that work on the CallExpression should be aware of the RawExpression handling.
// The interface will be dirty until we introduce subquery expression for RowExpression.
// With subqueries, the translation from Expression to RowExpression can happen here.
WindowNode.Function function = new WindowNode.Function(call(windowFunction.getName().toString(), analysis.getFunctionHandle(windowFunction), returnType, ((FunctionCall) rewritten).getArguments().stream().map(OriginalExpressionUtils::castToRowExpression).collect(toImmutableList())), frame, windowFunction.isIgnoreNulls());
ImmutableList.Builder<VariableReferenceExpression> orderByVariables = ImmutableList.builder();
orderByVariables.addAll(orderings.keySet());
Optional<OrderingScheme> orderingScheme = Optional.empty();
if (!orderings.isEmpty()) {
orderingScheme = Optional.of(new OrderingScheme(orderByVariables.build().stream().map(variable -> new Ordering(variable, orderings.get(variable))).collect(toImmutableList())));
}
// create window node
subPlan = new PlanBuilder(outputTranslations, new WindowNode(subPlan.getRoot().getSourceLocation(), idAllocator.getNextId(), subPlan.getRoot(), new WindowNode.Specification(partitionByVariables.build(), orderingScheme), ImmutableMap.of(newVariable, function), Optional.empty(), ImmutableSet.of(), 0));
if (needCoercion) {
subPlan = explicitCoercionVariables(subPlan, subPlan.getRoot().getOutputVariables(), ImmutableList.of(windowFunction));
}
}
return subPlan;
}
use of com.facebook.presto.spi.relation.CallExpression in project presto by prestodb.
the class StatisticsAggregationPlanner method createStatisticsAggregation.
public TableStatisticAggregation createStatisticsAggregation(TableStatisticsMetadata statisticsMetadata, Map<String, VariableReferenceExpression> columnToVariableMap, boolean useOriginalExpression) {
StatisticAggregationsDescriptor.Builder<VariableReferenceExpression> descriptor = StatisticAggregationsDescriptor.builder();
List<String> groupingColumns = statisticsMetadata.getGroupingColumns();
List<VariableReferenceExpression> groupingVariables = groupingColumns.stream().map(columnToVariableMap::get).collect(toImmutableList());
for (int i = 0; i < groupingVariables.size(); i++) {
descriptor.addGrouping(groupingColumns.get(i), groupingVariables.get(i));
}
ImmutableMap.Builder<VariableReferenceExpression, AggregationNode.Aggregation> aggregations = ImmutableMap.builder();
StandardFunctionResolution functionResolution = new FunctionResolution(metadata.getFunctionAndTypeManager());
for (TableStatisticType type : statisticsMetadata.getTableStatistics()) {
if (type != ROW_COUNT) {
throw new PrestoException(NOT_SUPPORTED, "Table-wide statistic type not supported: " + type);
}
AggregationNode.Aggregation aggregation = new AggregationNode.Aggregation(new CallExpression("count", functionResolution.countFunction(), BIGINT, ImmutableList.of()), Optional.empty(), Optional.empty(), false, Optional.empty());
VariableReferenceExpression variable = variableAllocator.newVariable("rowCount", BIGINT);
aggregations.put(variable, aggregation);
descriptor.addTableStatistic(ROW_COUNT, variable);
}
for (ColumnStatisticMetadata columnStatisticMetadata : statisticsMetadata.getColumnStatistics()) {
String columnName = columnStatisticMetadata.getColumnName();
ColumnStatisticType statisticType = columnStatisticMetadata.getStatisticType();
VariableReferenceExpression inputVariable = columnToVariableMap.get(columnName);
verify(inputVariable != null, "inputVariable is null");
ColumnStatisticsAggregation aggregation = createColumnAggregation(statisticType, inputVariable, useOriginalExpression);
VariableReferenceExpression variable = variableAllocator.newVariable(statisticType + ":" + columnName, aggregation.getOutputType());
aggregations.put(variable, aggregation.getAggregation());
descriptor.addColumnStatistic(columnStatisticMetadata, variable);
}
StatisticAggregations aggregation = new StatisticAggregations(aggregations.build(), groupingVariables);
return new TableStatisticAggregation(aggregation, descriptor.build());
}
use of com.facebook.presto.spi.relation.CallExpression in project presto by prestodb.
the class StatisticsAggregationPlanner method createAggregation.
private ColumnStatisticsAggregation createAggregation(String functionName, RowExpression input, Type inputType, Type outputType) {
FunctionAndTypeManager functionAndTypeManager = metadata.getFunctionAndTypeManager();
FunctionHandle functionHandle = functionAndTypeManager.lookupFunction(functionName, TypeSignatureProvider.fromTypes(ImmutableList.of(inputType)));
Type resolvedType = metadata.getType(getOnlyElement(functionAndTypeManager.getFunctionMetadata(functionHandle).getArgumentTypes()));
verify(resolvedType.equals(inputType), "resolved function input type does not match the input type: %s != %s", resolvedType, inputType);
return new ColumnStatisticsAggregation(new AggregationNode.Aggregation(new CallExpression(input.getSourceLocation(), functionName, functionHandle, outputType, ImmutableList.of(input)), Optional.empty(), Optional.empty(), false, Optional.empty()), outputType);
}
use of com.facebook.presto.spi.relation.CallExpression in project presto by prestodb.
the class AddIntermediateAggregations method outputsAsInputs.
/**
* Rewrite assignments so that inputs are in terms of the output symbols.
* <p>
* Example:
* 'a' := sum('b') => 'a' := sum('a')
* 'a' := count(*) => 'a' := count('a')
*/
private static Map<VariableReferenceExpression, Aggregation> outputsAsInputs(Map<VariableReferenceExpression, Aggregation> assignments) {
ImmutableMap.Builder<VariableReferenceExpression, Aggregation> builder = ImmutableMap.builder();
for (Map.Entry<VariableReferenceExpression, Aggregation> entry : assignments.entrySet()) {
VariableReferenceExpression output = entry.getKey();
Aggregation aggregation = entry.getValue();
checkState(!aggregation.getOrderBy().isPresent(), "Intermediate aggregation does not support ORDER BY");
builder.put(output, new Aggregation(new CallExpression(aggregation.getCall().getSourceLocation(), aggregation.getCall().getDisplayName(), aggregation.getCall().getFunctionHandle(), aggregation.getCall().getType(), ImmutableList.of(output)), Optional.empty(), Optional.empty(), false, // No mask for INTERMEDIATE
Optional.empty()));
}
return builder.build();
}
use of com.facebook.presto.spi.relation.CallExpression in project presto by prestodb.
the class TestPruneUnreferencedOutputs method windowNodePruning.
/**
* Test that the unreferenced output pruning works correctly when WindowNode is pruned as no downstream operators are consuming the window function output
*/
@Test
public void windowNodePruning() {
FunctionHandle functionHandle = createTestMetadataManager().getFunctionAndTypeManager().lookupFunction("rank", ImmutableList.of());
CallExpression call = call("rank", functionHandle, BIGINT);
WindowNode.Frame frame = new WindowNode.Frame(RANGE, UNBOUNDED_PRECEDING, Optional.empty(), UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty(), Optional.empty());
assertRuleApplication().on(p -> p.output(ImmutableList.of("user_uuid"), ImmutableList.of(p.variable("user_uuid", VARCHAR)), p.project(Assignments.of(p.variable("user_uuid", VARCHAR), p.variable("user_uuid", VARCHAR)), p.window(new WindowNode.Specification(ImmutableList.of(p.variable("user_uuid", VARCHAR)), Optional.of(new OrderingScheme(ImmutableList.of(new Ordering(p.variable("expr"), SortOrder.ASC_NULLS_LAST), new Ordering(p.variable("random"), SortOrder.ASC_NULLS_LAST))))), ImmutableMap.of(p.variable("rank"), new WindowNode.Function(call, frame, false)), p.project(Assignments.builder().put(p.variable("user_uuid", VARCHAR), p.variable("user_uuid", VARCHAR)).put(p.variable("expr", BIGINT), p.variable("expr", BIGINT)).put(p.variable("random", BIGINT), p.rowExpression("random()")).build(), p.values(p.variable("user_uuid", VARCHAR), p.variable("expr", BIGINT))))))).matches(output(project(project(values("user_uuid")))));
}
Aggregations