use of com.facebook.presto.sql.planner.plan.ProjectNode in project presto by prestodb.
the class TestEffectivePredicateExtractor method testProject.
@Test
public void testProject() throws Exception {
PlanNode node = new ProjectNode(newId(), filter(baseTableScan, and(equals(AE, BE), equals(BE, CE), lessThan(CE, bigintLiteral(10)))), Assignments.of(D, AE, E, CE));
Expression effectivePredicate = EffectivePredicateExtractor.extract(node, TYPES);
// Rewrite in terms of project output symbols
assertEquals(normalizeConjuncts(effectivePredicate), normalizeConjuncts(lessThan(DE, bigintLiteral(10)), equals(DE, EE)));
}
use of com.facebook.presto.sql.planner.plan.ProjectNode in project presto by prestodb.
the class TestCountConstantOptimizer method testCountConstantOptimizer.
@Test
public void testCountConstantOptimizer() throws Exception {
CountConstantOptimizer optimizer = new CountConstantOptimizer();
PlanNodeIdAllocator planNodeIdAllocator = new PlanNodeIdAllocator();
Symbol countAggregationSymbol = new Symbol("count");
Signature countAggregationSignature = new Signature("count", FunctionKind.AGGREGATE, parseTypeSignature(StandardTypes.BIGINT), parseTypeSignature(StandardTypes.BIGINT));
ImmutableMap<Symbol, FunctionCall> aggregations = ImmutableMap.of(countAggregationSymbol, new FunctionCall(QualifiedName.of("count"), ImmutableList.of(new SymbolReference("expr"))));
ImmutableMap<Symbol, Signature> functions = ImmutableMap.of(countAggregationSymbol, countAggregationSignature);
ValuesNode valuesNode = new ValuesNode(planNodeIdAllocator.getNextId(), ImmutableList.of(new Symbol("col")), ImmutableList.of(ImmutableList.of()));
AggregationNode eligiblePlan = new AggregationNode(planNodeIdAllocator.getNextId(), new ProjectNode(planNodeIdAllocator.getNextId(), valuesNode, Assignments.of(new Symbol("expr"), new LongLiteral("42"))), aggregations, functions, ImmutableMap.of(), ImmutableList.of(ImmutableList.of()), AggregationNode.Step.INTERMEDIATE, Optional.empty(), Optional.empty());
assertTrue(((AggregationNode) optimizer.optimize(eligiblePlan, TEST_SESSION, ImmutableMap.of(), new SymbolAllocator(), new PlanNodeIdAllocator())).getAggregations().get(countAggregationSymbol).getArguments().isEmpty());
AggregationNode ineligiblePlan = new AggregationNode(planNodeIdAllocator.getNextId(), new ProjectNode(planNodeIdAllocator.getNextId(), valuesNode, Assignments.of(new Symbol("expr"), new FunctionCall(QualifiedName.of("function"), ImmutableList.of(new Identifier("x"))))), aggregations, functions, ImmutableMap.of(), ImmutableList.of(ImmutableList.of()), AggregationNode.Step.INTERMEDIATE, Optional.empty(), Optional.empty());
assertFalse(((AggregationNode) optimizer.optimize(ineligiblePlan, TEST_SESSION, ImmutableMap.of(), new SymbolAllocator(), new PlanNodeIdAllocator())).getAggregations().get(countAggregationSymbol).getArguments().isEmpty());
}
use of com.facebook.presto.sql.planner.plan.ProjectNode in project presto by prestodb.
the class TestVerifyOnlyOneOutputNode method testValidateFailed.
@Test(expectedExceptions = IllegalStateException.class)
public void testValidateFailed() throws Exception {
// random plan with 2 output nodes
PlanNode root = new OutputNode(idAllocator.getNextId(), new ExplainAnalyzeNode(idAllocator.getNextId(), new OutputNode(idAllocator.getNextId(), new ProjectNode(idAllocator.getNextId(), new ValuesNode(idAllocator.getNextId(), ImmutableList.of(), ImmutableList.of()), Assignments.of()), ImmutableList.of(), ImmutableList.of()), new Symbol("a")), ImmutableList.of(), ImmutableList.of());
new VerifyOnlyOneOutputNode().validate(root, null, null, null, null);
}
use of com.facebook.presto.sql.planner.plan.ProjectNode in project presto by prestodb.
the class LogicalPlanner method createInsertPlan.
private RelationPlan createInsertPlan(Analysis analysis, Insert insertStatement) {
Analysis.Insert insert = analysis.getInsert().get();
TableMetadata tableMetadata = metadata.getTableMetadata(session, insert.getTarget());
List<ColumnMetadata> visibleTableColumns = tableMetadata.getColumns().stream().filter(column -> !column.isHidden()).collect(toImmutableList());
List<String> visibleTableColumnNames = visibleTableColumns.stream().map(ColumnMetadata::getName).collect(toImmutableList());
RelationPlan plan = createRelationPlan(analysis, insertStatement.getQuery());
Map<String, ColumnHandle> columns = metadata.getColumnHandles(session, insert.getTarget());
Assignments.Builder assignments = Assignments.builder();
for (ColumnMetadata column : tableMetadata.getColumns()) {
if (column.isHidden()) {
continue;
}
Symbol output = symbolAllocator.newSymbol(column.getName(), column.getType());
int index = insert.getColumns().indexOf(columns.get(column.getName()));
if (index < 0) {
assignments.put(output, new NullLiteral());
} else {
Symbol input = plan.getSymbol(index);
Type tableType = column.getType();
Type queryType = symbolAllocator.getTypes().get(input);
if (queryType.equals(tableType) || metadata.getTypeManager().isTypeOnlyCoercion(queryType, tableType)) {
assignments.put(output, input.toSymbolReference());
} else {
Expression cast = new Cast(input.toSymbolReference(), tableType.getTypeSignature().toString());
assignments.put(output, cast);
}
}
}
ProjectNode projectNode = new ProjectNode(idAllocator.getNextId(), plan.getRoot(), assignments.build());
List<Field> fields = visibleTableColumns.stream().map(column -> Field.newUnqualified(column.getName(), column.getType())).collect(toImmutableList());
Scope scope = Scope.builder().withRelationType(new RelationType(fields)).build();
plan = new RelationPlan(projectNode, scope, projectNode.getOutputSymbols());
Optional<NewTableLayout> newTableLayout = metadata.getInsertLayout(session, insert.getTarget());
return createTableWriterPlan(analysis, plan, new InsertReference(insert.getTarget()), visibleTableColumnNames, newTableLayout);
}
use of com.facebook.presto.sql.planner.plan.ProjectNode in project presto by prestodb.
the class QueryPlanner method aggregate.
private PlanBuilder aggregate(PlanBuilder subPlan, QuerySpecification node) {
List<List<Expression>> groupingSets = analysis.getGroupingSets(node);
if (groupingSets.isEmpty()) {
return subPlan;
}
// 1. Pre-project all scalar inputs (arguments and non-trivial group by expressions)
Set<Expression> distinctGroupingColumns = groupingSets.stream().flatMap(Collection::stream).collect(toImmutableSet());
ImmutableList.Builder<Expression> arguments = ImmutableList.builder();
analysis.getAggregates(node).stream().map(FunctionCall::getArguments).flatMap(List::stream).forEach(arguments::add);
// filter expressions need to be projected first
analysis.getAggregates(node).stream().map(FunctionCall::getFilter).filter(Optional::isPresent).map(Optional::get).forEach(arguments::add);
Iterable<Expression> inputs = Iterables.concat(distinctGroupingColumns, arguments.build());
subPlan = handleSubqueries(subPlan, node, inputs);
if (!Iterables.isEmpty(inputs)) {
// avoid an empty projection if the only aggregation is COUNT (which has no arguments)
subPlan = project(subPlan, inputs);
}
// 2. Aggregate
// 2.a. Rewrite aggregate arguments
TranslationMap argumentTranslations = new TranslationMap(subPlan.getRelationPlan(), analysis, lambdaDeclarationToSymbolMap);
ImmutableMap.Builder<Symbol, Symbol> argumentMappingBuilder = ImmutableMap.builder();
for (Expression argument : arguments.build()) {
Expression parametersReplaced = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(analysis.getParameters(), analysis), argument);
argumentTranslations.addIntermediateMapping(argument, parametersReplaced);
Symbol input = subPlan.translate(parametersReplaced);
if (!argumentTranslations.containsSymbol(parametersReplaced)) {
Symbol output = symbolAllocator.newSymbol(parametersReplaced, analysis.getTypeWithCoercions(parametersReplaced), "arg");
argumentMappingBuilder.put(output, input);
argumentTranslations.put(parametersReplaced, output);
}
}
Map<Symbol, Symbol> argumentMappings = argumentMappingBuilder.build();
// 2.b. Rewrite grouping columns
TranslationMap groupingTranslations = new TranslationMap(subPlan.getRelationPlan(), analysis, lambdaDeclarationToSymbolMap);
Map<Symbol, Symbol> groupingSetMappings = new HashMap<>();
List<List<Symbol>> groupingSymbols = new ArrayList<>();
for (List<Expression> groupingSet : groupingSets) {
ImmutableList.Builder<Symbol> symbols = ImmutableList.builder();
for (Expression expression : groupingSet) {
Expression parametersReplaced = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(analysis.getParameters(), analysis), expression);
groupingTranslations.addIntermediateMapping(expression, parametersReplaced);
Symbol input = subPlan.translate(expression);
Symbol output;
if (!groupingTranslations.containsSymbol(parametersReplaced)) {
output = symbolAllocator.newSymbol(parametersReplaced, analysis.getTypeWithCoercions(expression), "gid");
groupingTranslations.put(parametersReplaced, output);
} else {
output = groupingTranslations.get(parametersReplaced);
}
groupingSetMappings.put(output, input);
symbols.add(output);
}
groupingSymbols.add(symbols.build());
}
// 2.c. Generate GroupIdNode (multiple grouping sets) or ProjectNode (single grouping set)
Optional<Symbol> groupIdSymbol = Optional.empty();
if (groupingSets.size() > 1) {
groupIdSymbol = Optional.of(symbolAllocator.newSymbol("groupId", BIGINT));
GroupIdNode groupId = new GroupIdNode(idAllocator.getNextId(), subPlan.getRoot(), groupingSymbols, groupingSetMappings, argumentMappings, groupIdSymbol.get());
subPlan = new PlanBuilder(groupingTranslations, groupId, analysis.getParameters());
} else {
Assignments.Builder assignments = Assignments.builder();
for (Symbol output : argumentMappings.keySet()) {
assignments.put(output, argumentMappings.get(output).toSymbolReference());
}
for (Symbol output : groupingSetMappings.keySet()) {
assignments.put(output, groupingSetMappings.get(output).toSymbolReference());
}
ProjectNode project = new ProjectNode(idAllocator.getNextId(), subPlan.getRoot(), assignments.build());
subPlan = new PlanBuilder(groupingTranslations, project, analysis.getParameters());
}
TranslationMap aggregationTranslations = new TranslationMap(subPlan.getRelationPlan(), analysis, lambdaDeclarationToSymbolMap);
aggregationTranslations.copyMappingsFrom(groupingTranslations);
// 2.d. Rewrite aggregates
ImmutableMap.Builder<Symbol, FunctionCall> aggregationAssignments = ImmutableMap.builder();
ImmutableMap.Builder<Symbol, Signature> functions = ImmutableMap.builder();
boolean needPostProjectionCoercion = false;
for (FunctionCall aggregate : analysis.getAggregates(node)) {
Expression parametersReplaced = ExpressionTreeRewriter.rewriteWith(new ParameterRewriter(analysis.getParameters(), analysis), aggregate);
aggregationTranslations.addIntermediateMapping(aggregate, parametersReplaced);
Expression rewritten = argumentTranslations.rewrite(parametersReplaced);
Symbol newSymbol = symbolAllocator.newSymbol(rewritten, analysis.getType(aggregate));
// Therefore we can end up with this implicit cast, and have to move it into a post-projection
if (rewritten instanceof Cast) {
rewritten = ((Cast) rewritten).getExpression();
needPostProjectionCoercion = true;
}
aggregationAssignments.put(newSymbol, (FunctionCall) rewritten);
aggregationTranslations.put(parametersReplaced, newSymbol);
functions.put(newSymbol, analysis.getFunctionSignature(aggregate));
}
// 2.e. Mark distinct rows for each aggregate that has DISTINCT
// Map from aggregate function arguments to marker symbols, so that we can reuse the markers, if two aggregates have the same argument
Map<Set<Expression>, Symbol> argumentMarkers = new HashMap<>();
// Map from aggregate functions to marker symbols
Map<Symbol, Symbol> masks = new HashMap<>();
for (FunctionCall aggregate : Iterables.filter(analysis.getAggregates(node), FunctionCall::isDistinct)) {
Set<Expression> args = ImmutableSet.copyOf(aggregate.getArguments());
Symbol marker = argumentMarkers.get(args);
Symbol aggregateSymbol = aggregationTranslations.get(aggregate);
if (marker == null) {
if (args.size() == 1) {
marker = symbolAllocator.newSymbol(getOnlyElement(args), BOOLEAN, "distinct");
} else {
marker = symbolAllocator.newSymbol(aggregateSymbol.getName(), BOOLEAN, "distinct");
}
argumentMarkers.put(args, marker);
}
masks.put(aggregateSymbol, marker);
}
for (Map.Entry<Set<Expression>, Symbol> entry : argumentMarkers.entrySet()) {
ImmutableList.Builder<Symbol> builder = ImmutableList.builder();
builder.addAll(groupingSymbols.stream().flatMap(Collection::stream).distinct().collect(Collectors.toList()));
groupIdSymbol.ifPresent(builder::add);
for (Expression expression : entry.getKey()) {
builder.add(argumentTranslations.get(expression));
}
subPlan = subPlan.withNewRoot(new MarkDistinctNode(idAllocator.getNextId(), subPlan.getRoot(), entry.getValue(), builder.build(), Optional.empty()));
}
AggregationNode aggregationNode = new AggregationNode(idAllocator.getNextId(), subPlan.getRoot(), aggregationAssignments.build(), functions.build(), masks, groupingSymbols, AggregationNode.Step.SINGLE, Optional.empty(), groupIdSymbol);
subPlan = new PlanBuilder(aggregationTranslations, aggregationNode, analysis.getParameters());
// TODO: this is a hack, we should change type coercions to coerce the inputs to functions/operators instead of coercing the output
if (needPostProjectionCoercion) {
return explicitCoercionFields(subPlan, distinctGroupingColumns, analysis.getAggregates(node));
}
return subPlan;
}
Aggregations