class AliasedAnalyzedRelation implements AnalyzedRelation, FieldResolver {

    private final AnalyzedRelation relation;
    private final RelationName alias;
    private final Map<ColumnIdent, ColumnIdent> aliasToColumnMapping;
    private final ArrayList<Symbol> outputs;
    private final ArrayList<ScopedSymbol> scopedSymbols;

    public AliasedAnalyzedRelation(AnalyzedRelation relation, RelationName alias) {
        this(relation, alias, List.of());
    }

    AliasedAnalyzedRelation(AnalyzedRelation relation, RelationName alias, List<String> columnAliases) {
        this.relation = relation;
        this.alias = alias;
        aliasToColumnMapping = new HashMap<>(columnAliases.size());
        this.outputs = new ArrayList<>(relation.outputs().size());
        this.scopedSymbols = new ArrayList<>(relation.outputs().size());
        for (int i = 0; i < relation.outputs().size(); i++) {
            Symbol childOutput = relation.outputs().get(i);
            ColumnIdent childColumn = Symbols.pathFromSymbol(childOutput);
            ColumnIdent columnAlias = childColumn;
            if (i < columnAliases.size()) {
                columnAlias = new ColumnIdent(columnAliases.get(i));
            }
            aliasToColumnMapping.put(columnAlias, childColumn);
            var scopedSymbol = new ScopedSymbol(alias, columnAlias, childOutput.valueType());
            outputs.add(scopedSymbol);
            scopedSymbols.add(scopedSymbol);
        }
        for (int i = 0; i < relation.hiddenOutputs().size(); i++) {
            Symbol childOutput = relation.hiddenOutputs().get(i);
            ColumnIdent childColumn = Symbols.pathFromSymbol(childOutput);
            ColumnIdent columnAlias = childColumn;
            if (i + relation.outputs().size() < columnAliases.size()) {
                columnAlias = new ColumnIdent(columnAliases.get(i));
            }
            aliasToColumnMapping.putIfAbsent(columnAlias, childColumn);
        }
    }

    @Override
    public Symbol getField(ColumnIdent column, Operation operation, boolean errorOnUnknownObjectKey) throws AmbiguousColumnException, ColumnUnknownException, UnsupportedOperationException {
        if (operation != Operation.READ) {
            throw new UnsupportedOperationException(operation + " is not supported on " + alias);
        }
        ColumnIdent childColumnName = aliasToColumnMapping.get(column);
        if (childColumnName == null) {
            if (column.isRoot()) {
                return null;
            }
            childColumnName = aliasToColumnMapping.get(column.getRoot());
            if (childColumnName == null) {
                // The column ident maybe a quoted subscript which points to an alias of a sub relation.
                // Aliases are always strings but due to the support for quoted subscript expressions,
                // the select column ident may already be expanded to a subscript.
                var maybeQuotedSubscriptColumnAlias = new ColumnIdent(column.sqlFqn());
                childColumnName = aliasToColumnMapping.get(maybeQuotedSubscriptColumnAlias);
                if (childColumnName == null) {
                    return null;
                }
                column = maybeQuotedSubscriptColumnAlias;
            } else {
                childColumnName = new ColumnIdent(childColumnName.name(), column.path());
            }
        }
        Symbol field = relation.getField(childColumnName, operation, errorOnUnknownObjectKey);
        if (field == null) {
            return null;
        }
        if (field instanceof VoidReference voidReference) {
            return new VoidReference(
                new ReferenceIdent(alias, voidReference.column()),
                voidReference.position());
        }
        ScopedSymbol scopedSymbol = new ScopedSymbol(alias, column, field.valueType());

        // If the scopedSymbol exists already, return that instance.
        // Otherwise (e.g. lazy-loaded subscript expression) it must be stored to comply with
        // IdentityHashMap constraints.
        int i = scopedSymbols.indexOf(scopedSymbol);
        if (i >= 0) {
            return scopedSymbols.get(i);
        }
        scopedSymbols.add(scopedSymbol);
        return scopedSymbol;
    }

    public AnalyzedRelation relation() {
        return relation;
    }

    @Override
    public RelationName relationName() {
        return alias;
    }

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

    @Override
    public String toString() {
        return relation + " AS " + alias;
    }

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

    @Nullable
    @Override
    public Symbol resolveField(ScopedSymbol field) {<FILL_FUNCTION_BODY>}
}

        if (!field.relation().equals(alias)) {
            throw new IllegalArgumentException(field + " does not belong to " + relationName());
        }
        ColumnIdent column = field.column();
        ColumnIdent childColumnName = aliasToColumnMapping.get(column);
        if (childColumnName == null && !column.isRoot()) {
            var childCol = aliasToColumnMapping.get(column.getRoot());
            childColumnName = new ColumnIdent(childCol.name(), column.path());
        }
        assert childColumnName != null
            : "If a ScopedSymbol has been retrieved via `getField`, it must be possible to get the columnIdent";
        var result = relation.getField(childColumnName, Operation.READ);
        if (result == null) {
            throw new IllegalArgumentException(field + " does not belong to " + relationName());
        }
        return result;
    
<no_super_class>