class Eval extends ForwardingLogicalPlan {

    private final List<Symbol> outputs;

    public static LogicalPlan create(LogicalPlan source, List<Symbol> outputs) {<FILL_FUNCTION_BODY>}

    Eval(LogicalPlan source, List<Symbol> outputs) {
        super(source);
        this.outputs = outputs;
    }

    @Override
    public ExecutionPlan build(DependencyCarrier executor,
                               PlannerContext plannerContext,
                               Set<PlanHint> planHints,
                               ProjectionBuilder projectionBuilder,
                               int limit,
                               int offset,
                               @Nullable OrderBy order,
                               @Nullable Integer pageSizeHint,
                               Row params,
                               SubQueryResults subQueryResults) {
        ExecutionPlan executionPlan = source.build(
            executor, plannerContext, planHints, projectionBuilder, limit, offset, null, pageSizeHint, params, subQueryResults);
        if (outputs.equals(source.outputs())) {
            return executionPlan;
        }
        return addEvalProjection(plannerContext, executionPlan, params, subQueryResults);
    }

    @Override
    public List<Symbol> outputs() {
        return outputs;
    }

    @Override
    public LogicalPlan replaceSources(List<LogicalPlan> sources) {
        return new Eval(Lists.getOnlyElement(sources), outputs);
    }

    @Override
    public LogicalPlan pruneOutputsExcept(SequencedCollection<Symbol> outputsToKeep) {
        LogicalPlan newSource = source.pruneOutputsExcept(outputsToKeep);
        if (source == newSource) {
            return this;
        }
        return new Eval(newSource, List.copyOf(outputsToKeep));
    }

    @Nullable
    @Override
    public FetchRewrite rewriteToFetch(Collection<Symbol> usedColumns) {
        FetchRewrite fetchRewrite = source.rewriteToFetch(usedColumns);
        if (fetchRewrite == null) {
            return null;
        }
        LogicalPlan newSource = fetchRewrite.newPlan();
        UnaryOperator<Symbol> mapToFetchStubs = fetchRewrite.mapToFetchStubs();
        LinkedHashMap<Symbol, Symbol> newReplacedOutputs = new LinkedHashMap<>();
        ArrayList<Symbol> newOutputs = new ArrayList<>();
        for (Symbol sourceOutput : newSource.outputs()) {
            if (sourceOutput instanceof FetchMarker) {
                newOutputs.add(sourceOutput);
            }
        }
        for (Symbol output : outputs) {
            newReplacedOutputs.put(output, mapToFetchStubs.apply(output));
            if (SymbolVisitors.any(newSource.outputs()::contains, output)) {
                newOutputs.add(output);
            }
        }
        return new FetchRewrite(newReplacedOutputs, Eval.create(newSource, newOutputs));
    }

    private ExecutionPlan addEvalProjection(PlannerContext plannerContext,
                                            ExecutionPlan executionPlan,
                                            Row params,
                                            SubQueryResults subQueryResults) {
        PositionalOrderBy orderBy = executionPlan.resultDescription().orderBy();
        PositionalOrderBy newOrderBy = null;
        SubQueryAndParamBinder binder = new SubQueryAndParamBinder(params, subQueryResults);
        List<Symbol> boundOutputs = Lists.map(outputs, binder);
        if (orderBy != null) {
            newOrderBy = orderBy.tryMapToNewOutputs(source.outputs(), boundOutputs);
            if (newOrderBy == null) {
                executionPlan = Merge.ensureOnHandler(executionPlan, plannerContext);
            }
        }
        InputColumns.SourceSymbols ctx = new InputColumns.SourceSymbols(Lists.map(source.outputs(), binder));
        EvalProjection projection = new EvalProjection(InputColumns.create(boundOutputs, ctx));
        executionPlan.addProjection(
            projection,
            executionPlan.resultDescription().limit(),
            executionPlan.resultDescription().offset(),
            newOrderBy
        );
        return executionPlan;
    }

    @Override
    public String toString() {
        return "Eval{" +
               "src=" + source +
               ", out=" + outputs +
               '}';
    }

    @Override
    public <C, R> R accept(LogicalPlanVisitor<C, R> visitor, C context) {
        return visitor.visitEval(this, context);
    }
}

        if (source.outputs().equals(outputs)) {
            return source;
        }
        return new Eval(source, outputs);
    
<methods>public void <init>(io.crate.planner.operators.LogicalPlan) ,public Map<io.crate.planner.operators.LogicalPlan,io.crate.expression.symbol.SelectSymbol> dependencies() ,public List<io.crate.expression.symbol.Symbol> outputs() ,public io.crate.planner.operators.LogicalPlan pruneOutputsExcept(SequencedCollection<io.crate.expression.symbol.Symbol>) ,public List<io.crate.metadata.RelationName> relationNames() ,public io.crate.planner.operators.LogicalPlan source() ,public List<io.crate.planner.operators.LogicalPlan> sources() ,public boolean supportsDistributedReads() <variables>final non-sealed io.crate.planner.operators.LogicalPlan source,private final non-sealed List<io.crate.planner.operators.LogicalPlan> sources