class MapColumnsVisitor extends VoidExpressionVisitor {

    private ColumnResolver resolver;
    private int level;

    public MapColumnsVisitor(ColumnResolver resolver, int level) {
        this.resolver = resolver;
        this.level = level;
    }

    @Override
    public Void visitExpressionColumn(ExpressionColumn e) {
        e.mapColumns(resolver, level);
        return null;
    }

    @Override
    public Void visitSubQuery(SubQuery e) {
        level++;
        super.visitSubQuery(e);
        level--;
        return null;
    }

    @Override
    public Void visitConditionExists(ConditionExists e) {
        level++;
        super.visitConditionExists(e);
        level--;
        return null;
    }

    @Override
    public Void visitConditionIn(ConditionIn e) {
        int level = this.level;
        super.visitConditionIn(e);
        e.setQueryLevel(level);
        return null;
    }

    @Override
    public Void visitConditionInConstantSet(ConditionInConstantSet e) {
        int level = this.level;
        super.visitConditionInConstantSet(e);
        e.setQueryLevel(level);
        return null;
    }

    @Override
    public Void visitConditionInSelect(ConditionInSelect e) {
        e.getLeft().accept(this);
        level++;
        visitQuery(e.getQuery());
        level--;
        return null;
    }

    @Override
    public Void visitAggregate(Aggregate e) {
        // 聚合函数不能嵌套
        if (resolver.getState() == ColumnResolver.STATE_IN_AGGREGATE) {
            throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, e.getSQL());
        }
        if (e.getOn() != null) {
            int state = resolver.getState();
            resolver.setState(ColumnResolver.STATE_IN_AGGREGATE);
            try {
                super.visitAggregate(e);
            } finally {
                resolver.setState(state);
            }
        }
        return null;
    }

    @Override
    public Void visitAGroupConcat(AGroupConcat e) {
        // 聚合函数不能嵌套
        if (resolver.getState() == ColumnResolver.STATE_IN_AGGREGATE) {
            throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, e.getSQL());
        }
        int state = resolver.getState();
        resolver.setState(ColumnResolver.STATE_IN_AGGREGATE);
        try {
            super.visitAGroupConcat(e);
        } finally {
            resolver.setState(state);
        }
        return null;
    }

    @Override
    public Void visitJavaAggregate(JavaAggregate e) {<FILL_FUNCTION_BODY>}
}

        // 聚合函数不能嵌套
        if (resolver.getState() == ColumnResolver.STATE_IN_AGGREGATE) {
            throw DbException.get(ErrorCode.INVALID_USE_OF_AGGREGATE_FUNCTION_1, e.getSQL());
        }
        int state = resolver.getState();
        resolver.setState(ColumnResolver.STATE_IN_AGGREGATE);
        try {
            super.visitJavaAggregate(e);
        } finally {
            resolver.setState(state);
        }
        return null;
    
<methods>public non-sealed void <init>() ,public java.lang.Void visitAGroupConcat(com.lealone.sql.expression.aggregate.AGroupConcat) ,public java.lang.Void visitAggregate(com.lealone.sql.expression.aggregate.Aggregate) ,public java.lang.Void visitAlias(com.lealone.sql.expression.Alias) ,public java.lang.Void visitCompareLike(com.lealone.sql.expression.condition.CompareLike) ,public java.lang.Void visitComparison(com.lealone.sql.expression.condition.Comparison) ,public java.lang.Void visitConditionAndOr(com.lealone.sql.expression.condition.ConditionAndOr) ,public java.lang.Void visitConditionExists(com.lealone.sql.expression.condition.ConditionExists) ,public java.lang.Void visitConditionIn(com.lealone.sql.expression.condition.ConditionIn) ,public java.lang.Void visitConditionInConstantSet(com.lealone.sql.expression.condition.ConditionInConstantSet) ,public java.lang.Void visitConditionInSelect(com.lealone.sql.expression.condition.ConditionInSelect) ,public java.lang.Void visitConditionNot(com.lealone.sql.expression.condition.ConditionNot) ,public java.lang.Void visitExpression(com.lealone.sql.expression.Expression) ,public java.lang.Void visitExpressionColumn(com.lealone.sql.expression.ExpressionColumn) ,public java.lang.Void visitExpressionList(com.lealone.sql.expression.ExpressionList) ,public java.lang.Void visitFunction(com.lealone.sql.expression.function.Function) ,public java.lang.Void visitJavaAggregate(com.lealone.sql.expression.aggregate.JavaAggregate) ,public java.lang.Void visitJavaFunction(com.lealone.sql.expression.function.JavaFunction) ,public java.lang.Void visitOperation(com.lealone.sql.expression.Operation) ,public java.lang.Void visitParameter(com.lealone.sql.expression.Parameter) ,public java.lang.Void visitRownum(com.lealone.sql.expression.Rownum) ,public java.lang.Void visitSelect(com.lealone.sql.query.Select) ,public java.lang.Void visitSelectUnion(com.lealone.sql.query.SelectUnion) ,public java.lang.Void visitSequenceValue(com.lealone.sql.expression.SequenceValue) ,public java.lang.Void visitSubQuery(com.lealone.sql.expression.subquery.SubQuery) ,public java.lang.Void visitTableFunction(com.lealone.sql.expression.function.TableFunction) ,public java.lang.Void visitValueExpression(com.lealone.sql.expression.ValueExpression) ,public java.lang.Void visitVariable(com.lealone.sql.expression.Variable) ,public java.lang.Void visitWildcard(com.lealone.sql.expression.Wildcard) <variables>