private RelBuilder project_()

in core/src/main/java/org/apache/calcite/tools/RelBuilder.java [2080:2243]


  private RelBuilder project_(
      Iterable<? extends RexNode> nodes,
      Iterable<? extends @Nullable String> fieldNames,
      Iterable<RelHint> hints,
      boolean force,
      Iterable<CorrelationId> variablesSet) {
    final Frame frame = requireNonNull(peek_(), "frame stack is empty");
    final RelDataType inputRowType = frame.rel.getRowType();
    final List<RexNode> nodeList = Lists.newArrayList(nodes);
    final Set<CorrelationId> variables = ImmutableSet.copyOf(variablesSet);

    // Perform a quick check for identity. We'll do a deeper check
    // later when we've derived column names.
    if (!force && Iterables.isEmpty(fieldNames)
        && RexUtil.isIdentity(nodeList, inputRowType)) {
      return this;
    }

    final List<@Nullable String> fieldNameList = Lists.newArrayList(fieldNames);
    while (fieldNameList.size() < nodeList.size()) {
      fieldNameList.add(null);
    }

    // Do not merge projection when top projection has correlation variables
    bloat:
    if (frame.rel instanceof Project
        && config.bloat() >= 0
        && variables.isEmpty()) {
      final Project project = (Project) frame.rel;
      // Populate field names. If the upper expression is an input ref and does
      // not have a recommended name, use the name of the underlying field.
      for (int i = 0; i < fieldNameList.size(); i++) {
        if (fieldNameList.get(i) == null) {
          final RexNode node = nodeList.get(i);
          if (node instanceof RexInputRef) {
            final RexInputRef ref = (RexInputRef) node;
            fieldNameList.set(i,
                project.getRowType().getFieldNames().get(ref.getIndex()));
          }
        }
      }
      final List<RexNode> newNodes =
          RelOptUtil.pushPastProjectUnlessBloat(nodeList, project,
              config.bloat());
      if (newNodes == null) {
        // The merged expression is more complex than the input expressions.
        // Do not merge.
        break bloat;
      }

      // Carefully build a list of fields, so that table aliases from the input
      // can be seen for fields that are based on a RexInputRef.
      final Frame frame1 = stack.pop();
      final PairList<ImmutableSet<String>, RelDataTypeField> fields =
          PairList.of();
      project.getInput().getRowType().getFieldList()
          .forEach(f -> fields.add(ImmutableSet.of(), f));
      for (Pair<RexNode, ImmutableSet<String>> pair
          : Pair.zip(project.getProjects(), frame1.fields.leftList())) {
        switch (pair.left.getKind()) {
        case INPUT_REF:
          final int i = ((RexInputRef) pair.left).getIndex();
          fields.set(i, pair.right, fields.right(i));
          break;
        default:
          break;
        }
      }
      stack.push(new Frame(project.getInput(), fields));
      final ImmutableSet.Builder<RelHint> mergedHints = ImmutableSet.builder();
      mergedHints.addAll(project.getHints());
      mergedHints.addAll(hints);
      // Keep bottom projection's variablesSet.
      return project_(newNodes, fieldNameList, mergedHints.build(), force,
          ImmutableSet.copyOf(project.getVariablesSet()));
    }

    // Simplify expressions.
    if (config.simplify()) {
      nodeList.replaceAll(e -> simplifier.simplifyPreservingType(e));
    }

    // Replace null names with generated aliases.
    for (int i = 0; i < fieldNameList.size(); i++) {
      if (fieldNameList.get(i) == null) {
        fieldNameList.set(i, inferAlias(nodeList, nodeList.get(i), i));
      }
    }

    final PairList<ImmutableSet<String>, RelDataTypeField> fields =
        PairList.of();
    final Set<String> uniqueNameList =
        getTypeFactory().getTypeSystem().isSchemaCaseSensitive()
        ? new HashSet<>()
        : new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
    // calculate final names and build field list
    for (int i = 0; i < fieldNameList.size(); ++i) {
      final RexNode node = nodeList.get(i);
      String name = fieldNameList.get(i);
      String originalName = name;
      if (name == null || uniqueNameList.contains(name)) {
        int j = 0;
        if (name == null) {
          j = i;
        }
        do {
          name = SqlValidatorUtil.F_SUGGESTER.apply(originalName, j, j++);
        } while (uniqueNameList.contains(name));
        fieldNameList.set(i, name);
      }
      RelDataTypeField fieldType =
          new RelDataTypeFieldImpl(name, i, node.getType());
      switch (node.getKind()) {
      case INPUT_REF:
        // preserve rel aliases for INPUT_REF fields
        final int index = ((RexInputRef) node).getIndex();
        fields.add(frame.fields.left(index), fieldType);
        break;
      default:
        fields.add(ImmutableSet.of(), fieldType);
        break;
      }
      uniqueNameList.add(name);
    }
    if (!force && RexUtil.isIdentity(nodeList, inputRowType)) {
      if (fieldNameList.equals(inputRowType.getFieldNames())) {
        // Do not create an identity project if it does not rename any fields
        return this;
      } else {
        // create "virtual" row type for project only rename fields
        stack.pop();
        // Ignore the hints.
        stack.push(new Frame(frame.rel, fields));
      }
      return this;
    }

    // If the expressions are all literals, and the input is a Values with N
    // rows (or an Aggregate with 1 row), replace with a Values with same tuple
    // N times.
    final int rowCount;
    if (config.simplifyValues()
        && nodeList.stream().allMatch(e -> e instanceof RexLiteral)
        && (rowCount = fixedRowCount(frame)) >= 0) {
      RelNode unused = build();
      final RelDataTypeFactory.Builder typeBuilder = getTypeFactory().builder();
      Pair.forEach(fieldNameList, nodeList, (name, expr) ->
          typeBuilder.add(requireNonNull(name, "name"), expr.getType()));
      @SuppressWarnings({"unchecked", "rawtypes"})
      final List<RexLiteral> tuple = (List<RexLiteral>) (List) nodeList;
      return values(Collections.nCopies(rowCount, tuple),
          typeBuilder.build());
    }

    final RelNode project =
        struct.projectFactory.createProject(frame.rel,
            ImmutableList.copyOf(hints),
            ImmutableList.copyOf(nodeList),
            fieldNameList,
            variables);
    stack.pop();
    stack.push(new Frame(project, fields));
    return this;
  }