Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package com.facebook.presto.sql.planner.optimizations;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;

Re-maps symbol references that are just aliases of each other (e.g., due to projections like $0 := $1)

E.g.,

Output[$0, $1] -> Project[$0 := $2, $1 := $3 * 100] -> Aggregate[$2, $3 := sum($4)] -> ...

gets rewritten as

Output[$2, $1] -> Project[$2, $1 := $3 * 100] -> Aggregate[$2, $3 := sum($4)] -> ...

 
 public class UnaliasSymbolReferences
         extends PlanOptimizer
 {
     @Override
     public PlanNode optimize(PlanNode planSession sessionMap<SymbolTypetypesSymbolAllocator symbolAllocatorPlanNodeIdAllocator idAllocator)
     {
         checkNotNull(plan"plan is null");
         checkNotNull(session"session is null");
         checkNotNull(types"types is null");
         checkNotNull(symbolAllocator"symbolAllocator is null");
         checkNotNull(idAllocator"idAllocator is null");
 
         return PlanRewriter.rewriteWith(new Rewriter(new HashMap<SymbolSymbol>()), plan);
     }
 
     private static class Rewriter
             extends PlanRewriter<Void>
     {
         private final Map<SymbolSymbolmapping;
 
        public Rewriter(Map<SymbolSymbolmapping)
        {
            this. = mapping;
        }
        @Override
        public PlanNode visitAggregation(AggregationNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            ImmutableMap.Builder<SymbolSignaturefunctionInfos = ImmutableMap.builder();
            ImmutableMap.Builder<SymbolFunctionCallfunctionCalls = ImmutableMap.builder();
            ImmutableMap.Builder<SymbolSymbolmasks = ImmutableMap.builder();
            for (Map.Entry<SymbolFunctionCallentry : node.getAggregations().entrySet()) {
                Symbol symbol = entry.getKey();
                Symbol canonical = canonicalize(symbol);
                FunctionCall canonicalCall = (FunctionCallcanonicalize(entry.getValue());
                functionCalls.put(canonicalcanonicalCall);
                functionInfos.put(canonicalnode.getFunctions().get(symbol));
            }
            for (Map.Entry<SymbolSymbolentry : node.getMasks().entrySet()) {
                masks.put(canonicalize(entry.getKey()), canonicalize(entry.getValue()));
            }
            List<SymbolgroupByKeys = ImmutableList.copyOf(ImmutableSet.copyOf(canonicalize(node.getGroupBy())));
            return new AggregationNode(node.getId(), sourcegroupByKeysfunctionCalls.build(), functionInfos.build(), masks.build(), canonicalize(node.getSampleWeight()), node.getConfidence(), node.getHashSymbol());
        }
        @Override
        public PlanNode visitMarkDistinct(MarkDistinctNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            List<Symbolsymbols = ImmutableList.copyOf(ImmutableSet.copyOf(canonicalize(node.getDistinctSymbols())));
            return new MarkDistinctNode(node.getId(), sourcecanonicalize(node.getMarkerSymbol()), symbolsnode.getHashSymbol());
        }
        @Override
        public PlanNode visitUnnest(UnnestNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            ImmutableMap.Builder<SymbolList<Symbol>> builder = ImmutableMap.builder();
            for (Map.Entry<SymbolList<Symbol>> entry : node.getUnnestSymbols().entrySet()) {
                builder.put(canonicalize(entry.getKey()), canonicalize(entry.getValue()));
            }
            return new UnnestNode(node.getId(), sourcecanonicalize(node.getReplicateSymbols()), builder.build());
        }
        @Override
        public PlanNode visitWindow(WindowNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            ImmutableMap.Builder<SymbolSignaturefunctionInfos = ImmutableMap.builder();
            ImmutableMap.Builder<SymbolFunctionCallfunctionCalls = ImmutableMap.builder();
            for (Map.Entry<SymbolFunctionCallentry : node.getWindowFunctions().entrySet()) {
                Symbol symbol = entry.getKey();
                Symbol canonical = canonicalize(symbol);
                functionCalls.put(canonical, (FunctionCallcanonicalize(entry.getValue()));
                functionInfos.put(canonicalnode.getSignatures().get(symbol));
            }
            ImmutableMap.Builder<SymbolSortOrderorderings = ImmutableMap.builder();
            for (Map.Entry<SymbolSortOrderentry : node.getOrderings().entrySet()) {
                orderings.put(canonicalize(entry.getKey()), entry.getValue());
            }
            WindowNode.Frame frame = node.getFrame();
            frame = new WindowNode.Frame(frame.getType(),
                    frame.getStartType(), canonicalize(frame.getStartValue()),
                    frame.getEndType(), canonicalize(frame.getEndValue()));
            return new WindowNode(node.getId(), sourcecanonicalize(node.getPartitionBy()), canonicalize(node.getOrderBy()), orderings.build(), framefunctionCalls.build(), functionInfos.build(), node.getHashSymbol());
        }
        @Override
        public PlanNode visitTableScan(TableScanNode nodeRewriteContext<Voidcontext)
        {
            ImmutableMap.Builder<SymbolColumnHandlebuilder = ImmutableMap.builder();
            for (Map.Entry<SymbolColumnHandleentry : node.getAssignments().entrySet()) {
                builder.put(canonicalize(entry.getKey()), entry.getValue());
            }
            Expression originalConstraint = null;
            if (node.getOriginalConstraint() != null) {
                originalConstraint = canonicalize(node.getOriginalConstraint());
            }
            return new TableScanNode(node.getId(), node.getTable(), canonicalize(node.getOutputSymbols()), builder.build(), originalConstraintnode.getSummarizedPartition());
        }
        @Override
        public PlanNode visitFilter(FilterNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            return new FilterNode(node.getId(), sourcecanonicalize(node.getPredicate()));
        }
        @Override
        public PlanNode visitProject(ProjectNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            Map<ExpressionSymbolcomputedExpressions = new HashMap<>();
            Map<SymbolExpressionassignments = new LinkedHashMap<>();
            for (Map.Entry<SymbolExpressionentry : node.getAssignments().entrySet()) {
                Expression expression = canonicalize(entry.getValue());
                if (entry.getValue() instanceof QualifiedNameReference) {
                    // Always map a trivial symbol projection
                    Symbol symbol = Symbol.fromQualifiedName(((QualifiedNameReferenceentry.getValue()).getName());
                    if (!symbol.equals(entry.getKey())) {
                        map(entry.getKey(), symbol);
                    }
                }
                else if (DeterminismEvaluator.isDeterministic(expression) && !(expression instanceof NullLiteral)) {
                    // Try to map same deterministic expressions within a projection into the same symbol
                    // Omit NullLiterals since those have ambiguous types
                    Symbol computedSymbol = computedExpressions.get(expression);
                    if (computedSymbol == null) {
                        // If we haven't seen the expression before in this projection, record it
                        computedExpressions.put(expressionentry.getKey());
                    }
                    else {
                        // If we have seen the expression before and if it is deterministic
                        // then we can rewrite references to the current symbol in terms of the parallel computedSymbol in the projection
                        map(entry.getKey(), computedSymbol);
                    }
                }
                Symbol canonical = canonicalize(entry.getKey());
                if (!assignments.containsKey(canonical)) {
                    assignments.put(canonicalexpression);
                }
            }
            return new ProjectNode(node.getId(), sourceassignments);
        }
        @Override
        public PlanNode visitOutput(OutputNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            List<Symbolcanonical = Lists.transform(node.getOutputSymbols(), this::canonicalize);
            return new OutputNode(node.getId(), sourcenode.getColumnNames(), canonical);
        }
        @Override
        public PlanNode visitTopN(TopNNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            ImmutableList.Builder<Symbolsymbols = ImmutableList.builder();
            ImmutableMap.Builder<SymbolSortOrderorderings = ImmutableMap.builder();
            for (Symbol symbol : node.getOrderBy()) {
                Symbol canonical = canonicalize(symbol);
                symbols.add(canonical);
                orderings.put(canonicalnode.getOrderings().get(symbol));
            }
            return new TopNNode(node.getId(), sourcenode.getCount(), symbols.build(), orderings.build(), node.isPartial());
        }
        @Override
        public PlanNode visitSort(SortNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            ImmutableList.Builder<Symbolsymbols = ImmutableList.builder();
            ImmutableMap.Builder<SymbolSortOrderorderings = ImmutableMap.builder();
            for (Symbol symbol : node.getOrderBy()) {
                Symbol canonical = canonicalize(symbol);
                symbols.add(canonical);
                orderings.put(canonicalnode.getOrderings().get(symbol));
            }
            return new SortNode(node.getId(), sourcesymbols.build(), orderings.build());
        }
        @Override
        public PlanNode visitJoin(JoinNode nodeRewriteContext<Voidcontext)
        {
            PlanNode left = context.rewrite(node.getLeft());
            PlanNode right = context.rewrite(node.getRight());
            return new JoinNode(node.getId(), node.getType(), leftrightcanonicalizeJoinCriteria(node.getCriteria()), node.getLeftHashSymbol(), node.getRightHashSymbol());
        }
        @Override
        public PlanNode visitSemiJoin(SemiJoinNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            PlanNode filteringSource = context.rewrite(node.getFilteringSource());
            return new SemiJoinNode(node.getId(), sourcefilteringSourcecanonicalize(node.getSourceJoinSymbol()), canonicalize(node.getFilteringSourceJoinSymbol()), canonicalize(node.getSemiJoinOutput()), node.getSourceHashSymbol(), node.getFilteringSourceHashSymbol());
        }
        @Override
        public PlanNode visitIndexSource(IndexSourceNode nodeRewriteContext<Voidcontext)
        {
            ImmutableMap.Builder<SymbolColumnHandlebuilder = ImmutableMap.builder();
            for (Map.Entry<SymbolColumnHandleentry : node.getAssignments().entrySet()) {
                builder.put(canonicalize(entry.getKey()), entry.getValue());
            }
            return new IndexSourceNode(node.getId(), node.getIndexHandle(), node.getTableHandle(), canonicalize(node.getLookupSymbols()), canonicalize(node.getOutputSymbols()), builder.build(), node.getEffectiveTupleDomain());
        }
        @Override
        public PlanNode visitIndexJoin(IndexJoinNode nodeRewriteContext<Voidcontext)
        {
            PlanNode probeSource = context.rewrite(node.getProbeSource());
            PlanNode indexSource = context.rewrite(node.getIndexSource());
            return new IndexJoinNode(node.getId(), node.getType(), probeSourceindexSourcecanonicalizeIndexJoinCriteria(node.getCriteria()), node.getProbeHashSymbol(), node.getIndexHashSymbol());
        }
        @Override
        public PlanNode visitUnion(UnionNode nodeRewriteContext<Voidcontext)
        {
            ImmutableList.Builder<PlanNoderewrittenSources = ImmutableList.builder();
            for (PlanNode source : node.getSources()) {
                rewrittenSources.add(context.rewrite(source));
            }
            return new UnionNode(node.getId(), rewrittenSources.build(), canonicalizeUnionSymbolMap(node.getSymbolMapping()));
        }
        @Override
        public PlanNode visitTableWriter(TableWriterNode nodeRewriteContext<Voidcontext)
        {
            PlanNode source = context.rewrite(node.getSource());
            return new TableWriterNode(node.getId(), sourcenode.getTarget(), canonicalize(node.getColumns()), node.getColumnNames(), canonicalize(node.getOutputSymbols()), canonicalize(node.getSampleWeightSymbol()));
        }
        private void map(Symbol symbolSymbol canonical)
        {
            Preconditions.checkArgument(!symbol.equals(canonical), "Can't map symbol to itself: %s"symbol);
            .put(symbolcanonical);
        }
        private Optional<Symbolcanonicalize(Optional<Symbolsymbol)
        {
            if (symbol.isPresent()) {
                return Optional.of(canonicalize(symbol.get()));
            }
            return Optional.empty();
        }
        private Symbol canonicalize(Symbol symbol)
        {
            Symbol canonical = symbol;
            while (.containsKey(canonical)) {
                canonical = .get(canonical);
            }
            return canonical;
        }
        private Expression canonicalize(Expression value)
        {
            return ExpressionTreeRewriter.rewriteWith(new ExpressionRewriter<Void>()
            {
                @Override
                public Expression rewriteQualifiedNameReference(QualifiedNameReference nodeVoid contextExpressionTreeRewriter<VoidtreeRewriter)
                {
                    Symbol canonical = canonicalize(Symbol.fromQualifiedName(node.getName()));
                    return new QualifiedNameReference(canonical.toQualifiedName());
                }
            }, value);
        }
        private List<Symbolcanonicalize(List<Symboloutputs)
        {
            return Lists.transform(outputsthis::canonicalize);
        }
        private Set<Symbolcanonicalize(Set<Symbolsymbols)
        {
            return FluentIterable.from(symbols)
                    .transform(this::canonicalize)
                    .toSet();
        }
        {
            ImmutableList.Builder<JoinNode.EquiJoinClausebuilder = ImmutableList.builder();
            for (JoinNode.EquiJoinClause clause : criteria) {
                builder.add(new JoinNode.EquiJoinClause(canonicalize(clause.getLeft()), canonicalize(clause.getRight())));
            }
            return builder.build();
        }
        {
            ImmutableList.Builder<IndexJoinNode.EquiJoinClausebuilder = ImmutableList.builder();
            for (IndexJoinNode.EquiJoinClause clause : criteria) {
                builder.add(new IndexJoinNode.EquiJoinClause(canonicalize(clause.getProbe()), canonicalize(clause.getIndex())));
            }
            return builder.build();
        }
        private ListMultimap<SymbolSymbolcanonicalizeUnionSymbolMap(ListMultimap<SymbolSymbolunionSymbolMap)
        {
            ImmutableListMultimap.Builder<SymbolSymbolbuilder = ImmutableListMultimap.builder();
            for (Map.Entry<SymbolCollection<Symbol>> entry : unionSymbolMap.asMap().entrySet()) {
                builder.putAll(canonicalize(entry.getKey()), Iterables.transform(entry.getValue(), this::canonicalize));
            }
            return builder.build();
        }
    }
New to GrepCode? Check out our FAQ X