@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());
  }
예제 #2
0
      @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);
      }
예제 #3
0
 @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);
 }
예제 #4
0
    @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));
    }
예제 #6
0
    @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);
    }
예제 #7
0
 @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);
 }
예제 #8
0
  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));
  }
예제 #9
0
    @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());
    }
예제 #10
0
    @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()));
    }
예제 #11
0
 @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;
 }