@Override public Expression visitProject(ProjectNode node, Void context) { // TODO: add simple algebraic solver for projection translation (right now only considers // identity projections) Expression underlyingPredicate = node.getSource().accept(this, context); Iterable<Expression> projectionEqualities = transform( filter(node.getOutputMap().entrySet(), not(symbolMatchesExpression())), new Function<Map.Entry<Symbol, Expression>, Expression>() { @Override public Expression apply(Map.Entry<Symbol, Expression> entry) { QualifiedNameReference reference = new QualifiedNameReference(entry.getKey().toQualifiedName()); Expression expression = entry.getValue(); return new ComparisonExpression( ComparisonExpression.Type.EQUAL, reference, expression); } }); return pullExpressionThroughSymbols( combineConjuncts( ImmutableList.<Expression>builder() .addAll(projectionEqualities) .add(underlyingPredicate) .build()), node.getOutputSymbols()); }
@Override public Map<Symbol, Symbol> visitProject(ProjectNode node, Set<Symbol> lookupSymbols) { // Map from output Symbols to source Symbols Map<Symbol, Symbol> directSymbolTranslationOutputMap = Maps.transformValues( Maps.filterValues(node.getAssignments(), SymbolReference.class::isInstance), Symbol::from); Map<Symbol, Symbol> outputToSourceMap = lookupSymbols .stream() .filter(directSymbolTranslationOutputMap.keySet()::contains) .collect(toImmutableMap(identity(), directSymbolTranslationOutputMap::get)); checkState( !outputToSourceMap.isEmpty(), "No lookup symbols were able to pass through the projection"); // Map from source Symbols to underlying index source Symbols Map<Symbol, Symbol> sourceToIndexMap = node.getSource().accept(this, ImmutableSet.copyOf(outputToSourceMap.values())); // Generate the Map the connects lookup symbols to underlying index source symbols Map<Symbol, Symbol> outputToIndexMap = Maps.transformValues( Maps.filterValues(outputToSourceMap, in(sourceToIndexMap.keySet())), Functions.forMap(sourceToIndexMap)); return ImmutableMap.copyOf(outputToIndexMap); }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); Map<Symbol, Expression> assignments = ImmutableMap.copyOf( Maps.transformValues(node.getAssignments(), this::simplifyExpression)); return new ProjectNode(node.getId(), source, assignments); }
@Override public ActualProperties visitProject(ProjectNode node, List<ActualProperties> inputProperties) { ActualProperties properties = Iterables.getOnlyElement(inputProperties); Map<Symbol, Symbol> identities = computeIdentityTranslations(node.getAssignments()); ActualProperties translatedProperties = properties.translate(column -> Optional.ofNullable(identities.get(column))); // Extract additional constants Map<Symbol, NullableValue> constants = new HashMap<>(); for (Map.Entry<Symbol, Expression> assignment : node.getAssignments().entrySet()) { Expression expression = assignment.getValue(); IdentityHashMap<Expression, Type> expressionTypes = getExpressionTypes( session, metadata, parser, types, expression, emptyList() /* parameters already replaced */); Type type = requireNonNull(expressionTypes.get(expression)); ExpressionInterpreter optimizer = ExpressionInterpreter.expressionOptimizer( expression, metadata, session, expressionTypes); // TODO: // We want to use a symbol resolver that looks up in the constants from the input subplan // to take advantage of constant-folding for complex expressions // However, that currently causes errors when those expressions operate on arrays or row // types // ("ROW comparison not supported for fields with null elements", etc) Object value = optimizer.optimize(NoOpSymbolResolver.INSTANCE); if (value instanceof SymbolReference) { Symbol symbol = Symbol.from((SymbolReference) value); NullableValue existingConstantValue = constants.get(symbol); if (existingConstantValue != null) { constants.put(assignment.getKey(), new NullableValue(type, value)); } } else if (!(value instanceof Expression)) { constants.put(assignment.getKey(), new NullableValue(type, value)); } } constants.putAll(translatedProperties.getConstants()); return ActualProperties.builderFrom(translatedProperties).constants(constants).build(); }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Void> context) { PlanNode source = context.rewrite(node.getSource()); if (!node.getOutputSymbols().equals(source.getOutputSymbols())) { // Can't get rid of this projection. It constrains the output tuple from the underlying // operator return replaceChildren(node, ImmutableList.of(source)); } if (node.isIdentity()) { return source; } return replaceChildren(node, ImmutableList.of(source)); }
@Override public Void visitProject(ProjectNode node, Void context) { StringBuilder builder = new StringBuilder(); for (Map.Entry<Symbol, Expression> entry : node.getOutputMap().entrySet()) { if ((entry.getValue() instanceof QualifiedNameReference) && ((QualifiedNameReference) entry.getValue()) .getName() .equals(entry.getKey().toQualifiedName())) { // skip identity assignments continue; } builder.append(format("%s := %s\\n", entry.getKey(), entry.getValue())); } printNode(node, "Project", builder.toString(), NODE_COLORS.get(NodeType.PROJECT)); return node.getSource().accept(this, context); }
@Override public PlanNode rewriteProject( ProjectNode node, Expression inheritedPredicate, PlanRewriter<Expression> planRewriter) { Expression inlinedPredicate = ExpressionTreeRewriter.rewriteWith( new ExpressionSymbolInliner(node.getOutputMap()), inheritedPredicate); return planRewriter.defaultRewrite(node, inlinedPredicate); }
private RelationPlan addConstantSampleWeight(RelationPlan subPlan) { ImmutableMap.Builder<Symbol, Expression> projections = ImmutableMap.builder(); for (Symbol symbol : subPlan.getOutputSymbols()) { Expression expression = new QualifiedNameReference(symbol.toQualifiedName()); projections.put(symbol, expression); } Expression one = new LongLiteral("1"); Symbol sampleWeightSymbol = symbolAllocator.newSymbol("$sampleWeight", BIGINT); projections.put(sampleWeightSymbol, one); ProjectNode projectNode = new ProjectNode(idAllocator.getNextId(), subPlan.getRoot(), projections.build()); return new RelationPlan( projectNode, subPlan.getDescriptor(), projectNode.getOutputSymbols(), Optional.of(sampleWeightSymbol)); }
@Override public PlanNode visitProject(ProjectNode node, RewriteContext<Set<Symbol>> context) { ImmutableSet.Builder<Symbol> expectedInputs = ImmutableSet.builder(); ImmutableMap.Builder<Symbol, Expression> builder = ImmutableMap.builder(); for (int i = 0; i < node.getOutputSymbols().size(); i++) { Symbol output = node.getOutputSymbols().get(i); Expression expression = node.getAssignments().get(output); if (context.get().contains(output)) { expectedInputs.addAll(DependencyExtractor.extractUnique(expression)); builder.put(output, expression); } } PlanNode source = context.rewrite(node.getSource(), expectedInputs.build()); return new ProjectNode(node.getId(), source, builder.build()); }
@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 public SubPlanBuilder visitProject(ProjectNode node, Void context) { SubPlanBuilder current = node.getSource().accept(this, context); current.setRoot(new ProjectNode(node.getId(), current.getRoot(), node.getOutputMap())); return current; }