class SysUpdateProjection extends Projection {

    private final Symbol uidSymbol;

    private Map<Reference, Symbol> assignments;

    private Symbol[] outputs;

    @Nullable
    private Symbol[] returnValues;

    public SysUpdateProjection(Symbol uidSymbol,
                               Map<Reference, Symbol> assignments,
                               Symbol[] outputs,
                               @Nullable Symbol[] returnValues
    ) {
        this.uidSymbol = uidSymbol;
        this.assignments = assignments;
        this.returnValues = returnValues;
        assert Arrays.stream(outputs).noneMatch(s -> SymbolVisitors.any(Symbols.IS_COLUMN.or(x -> x instanceof SelectSymbol), s))
            : "Cannot operate on Reference, Field or SelectSymbol symbols: " + outputs;
        this.outputs = outputs;
    }

    public SysUpdateProjection(StreamInput in) throws IOException {
        uidSymbol = Symbols.fromStream(in);
        int numAssignments = in.readVInt();
        assignments = new HashMap<>(numAssignments, 1.0f);
        for (int i = 0; i < numAssignments; i++) {
            assignments.put(Reference.fromStream(in), Symbols.fromStream(in));
        }
        if (in.getVersion().onOrAfter(Version.V_4_2_0)) {
            int outputSize = in.readVInt();
            outputs = new Symbol[outputSize];
            for (int i = 0; i < outputSize; i++) {
                outputs[i] = Symbols.fromStream(in);
            }
            int returnValuesSize = in.readVInt();
            if (returnValuesSize > 0) {
                returnValues = new Symbol[returnValuesSize];
                for (int i = 0; i < returnValuesSize; i++) {
                    returnValues[i] = Symbols.fromStream(in);
                }
            }
        } else {
            //Outputs should never be null and for BwC reasons
            //the default value in pre 4.1 was a long for a count
            outputs = new Symbol[]{new InputColumn(0, DataTypes.LONG)};
        }
    }

    @Override
    public ProjectionType projectionType() {
        return ProjectionType.SYS_UPDATE;
    }

    @Nullable
    public Symbol[] returnValues() {
        return returnValues;
    }

    @Override
    public List<? extends Symbol> outputs() {
        return List.of(outputs);
    }

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

    public Map<Reference, Symbol> assignments() {
        return assignments;
    }

    @Override
    public void writeTo(StreamOutput out) throws IOException {<FILL_FUNCTION_BODY>}

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        SysUpdateProjection that = (SysUpdateProjection) o;
        return Objects.equals(uidSymbol, that.uidSymbol) &&
               Objects.equals(assignments, that.assignments) &&
               Arrays.equals(outputs, that.outputs) &&
               Arrays.equals(returnValues, that.returnValues);
    }

    @Override
    public int hashCode() {
        int result = Objects.hash(super.hashCode(), uidSymbol, assignments);
        result = 31 * result + Arrays.hashCode(outputs);
        result = 31 * result + Arrays.hashCode(returnValues);
        return result;
    }

    @Override
    public RowGranularity requiredGranularity() {
        return RowGranularity.NODE;
    }
}

        Symbols.toStream(uidSymbol, out);
        out.writeVInt(assignments.size());
        for (Map.Entry<Reference, Symbol> e : assignments.entrySet()) {
            Reference.toStream(out, e.getKey());
            Symbols.toStream(e.getValue(), out);
        }

        if (out.getVersion().onOrAfter(Version.V_4_2_0)) {
            out.writeVInt(outputs.length);
            for (int i = 0; i < outputs.length; i++) {
                Symbols.toStream(outputs[i], out);
            }
            if (returnValues != null) {
                out.writeVInt(returnValues.length);
                for (int i = 0; i < returnValues.length; i++) {
                    Symbols.toStream(returnValues[i], out);
                }
            } else {
                out.writeVInt(0);
            }
        }
    
<methods>public non-sealed void <init>() ,public abstract R accept(ProjectionVisitor<C,R>, C) ,public abstract boolean equals(java.lang.Object) ,public static io.crate.execution.dsl.projection.Projection fromStream(org.elasticsearch.common.io.stream.StreamInput) throws java.io.IOException,public int hashCode() ,public Map<java.lang.String,java.lang.Object> mapRepresentation() ,public abstract List<? extends io.crate.expression.symbol.Symbol> outputs() ,public abstract io.crate.execution.dsl.projection.ProjectionType projectionType() ,public io.crate.metadata.RowGranularity requiredGranularity() ,public static void toStream(io.crate.execution.dsl.projection.Projection, org.elasticsearch.common.io.stream.StreamOutput) throws java.io.IOException,public abstract void writeTo(org.elasticsearch.common.io.stream.StreamOutput) throws java.io.IOException<variables>static final Predicate<io.crate.execution.dsl.projection.Projection> IS_NODE_PROJECTION,static final Predicate<io.crate.execution.dsl.projection.Projection> IS_SHARD_PROJECTION