@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Context> context) { if (node.getSource() instanceof TableScanNode) { return planTableScan((TableScanNode) node.getSource(), node.getPredicate(), context.get()); } return context.defaultRewrite( node, new Context(context.get().getLookupSymbols(), context.get().getSuccess())); }
@Override public PlanNode visitFilter(FilterNode node, RewriteContext<Void> context) { if (node.getSource() instanceof TableScanNode && !((TableScanNode) node.getSource()).getLayout().isPresent()) { return planTableScan((TableScanNode) node.getSource(), node.getPredicate()); } return context.defaultRewrite(node); }
@Override public PlanNode visitOutput(OutputNode node, RewriteContext<FragmentProperties> context) { context .get() .setSingleNodeDistribution() // TODO: add support for distributed output .setOutputLayout(node.getOutputSymbols()) .setUnpartitionedOutput(); return context.defaultRewrite(node, context.get()); }
@Override public PlanNode visitTableCommit(TableCommitNode node, RewriteContext<Void> context) { Optional<DeleteNode> delete = findNode(node.getSource(), DeleteNode.class); if (!delete.isPresent()) { return context.defaultRewrite(node); } Optional<TableScanNode> tableScan = findNode(delete.get().getSource(), TableScanNode.class); if (!tableScan.isPresent()) { return context.defaultRewrite(node); } TableScanNode tableScanNode = tableScan.get(); if (!metadata.supportsMetadataDelete( session, tableScanNode.getTable(), tableScanNode.getLayout().get())) { return context.defaultRewrite(node); } return new MetadataDeleteNode( idAllocator.getNextId(), delete.get().getTarget(), Iterables.getOnlyElement(node.getOutputSymbols()), tableScanNode.getLayout().get()); }
@Override public PlanNode visitWindow(WindowNode node, RewriteContext<Context> context) { if (!node.getWindowFunctions() .values() .stream() .map(function -> function.getFunctionCall().getName()) .allMatch(metadata.getFunctionRegistry()::isAggregationFunction)) { return node; } // Don't need this restriction if we can prove that all order by symbols are deterministically // produced if (!node.getOrderBy().isEmpty()) { return node; } // Only RANGE frame type currently supported for aggregation functions because it guarantees // the // same value for each peer group. // ROWS frame type requires the ordering to be fully deterministic (e.g. deterministically // sorted on all columns) if (node.getFrames() .stream() .map(WindowNode.Frame::getType) .anyMatch( type -> type != WindowFrame.Type .RANGE)) { // TODO: extract frames of type RANGE and allow optimization on // them return node; } // Lookup symbols can only be passed through if they are part of the partitioning Set<Symbol> partitionByLookupSymbols = context .get() .getLookupSymbols() .stream() .filter(node.getPartitionBy()::contains) .collect(toImmutableSet()); if (partitionByLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite( node, new Context(partitionByLookupSymbols, context.get().getSuccess())); }
@Override public PlanNode visitAggregation(AggregationNode node, RewriteContext<Context> context) { // Lookup symbols can only be passed through if they are part of the group by columns Set<Symbol> groupByLookupSymbols = context .get() .getLookupSymbols() .stream() .filter(node.getGroupingKeys()::contains) .collect(toImmutableSet()); if (groupByLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite( node, new Context(groupByLookupSymbols, context.get().getSuccess())); }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Context> context) { // Rewrite the lookup symbols in terms of only the pre-projected symbols that have direct // translations Set<Symbol> newLookupSymbols = context .get() .getLookupSymbols() .stream() .map(node.getAssignments()::get) .filter(SymbolReference.class::isInstance) .map(Symbol::from) .collect(toImmutableSet()); if (newLookupSymbols.isEmpty()) { return node; } return context.defaultRewrite( node, new Context(newLookupSymbols, context.get().getSuccess())); }
@Override protected PlanNode visitPlan(PlanNode node, RewriteContext<Void> context) { return context.defaultRewrite(node); }
@Override public PlanNode visitValues(ValuesNode node, RewriteContext<FragmentProperties> context) { context.get().setSingleNodeDistribution(); return context.defaultRewrite(node, context.get()); }
@Override public PlanNode visitTableScan(TableScanNode node, RewriteContext<FragmentProperties> context) { context.get().setSourceDistribution(node.getId()); return context.defaultRewrite(node, context.get()); }
@Override public PlanNode visitMetadataDelete( MetadataDeleteNode node, RewriteContext<FragmentProperties> context) { context.get().setCoordinatorOnlyDistribution(); return context.defaultRewrite(node, context.get()); }