001package gudusoft.gsqlparser.resolver;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.TContext;
005import gudusoft.gsqlparser.compiler.TScope;
006
007import gudusoft.gsqlparser.nodes.*;
008
009import java.util.Stack;
010
011/**
012 * TRelationResolver 负责为SQL语句中的每个表收集和初始化属性(attributes)。
013 * 这些属性主要包含表的列信息,用于后续解析器(如TAttributeResolver)建立表和列之间的关系。
014 * 
015 * 工作流程:
016 * 1. 遍历SQL语句中的所有表
017 * 2. 根据表的类型(普通表、函数表、子查询等)收集属性
018 * 3. 将属性存储在TTable.attributes中
019 * 
020 * 属性来源:
021 * - 普通表:从数据库元数据(TSQLTable)获取列信息
022 * - 函数表:从函数定义获取返回列
023 * - 子查询:由TAttributeResolver处理
024 * - XML表:从XML表定义获取列
025 * - 表达式:生成通配符属性
026 */
027public class TRelationResolver2 extends TParseTreeVisitor {
028    private final TContext globalScope;        // 全局上下文,包含SQL环境
029    private final TStatementList sqlStatements; // 要分析的SQL语句列表
030    private final Stack<TScope> scopeStack;    // 作用域栈,用于维护嵌套关系
031
032    /**
033     * 创建关系解析器实例。
034     * @param sqls 要分析的SQL语句列表
035     * @param scope 包含SQL环境的全局上下文
036     */
037    public TRelationResolver2(TStatementList sqls, TContext scope) {
038        this.globalScope = scope;
039        this.sqlStatements = sqls;
040        this.scopeStack = new Stack<>();
041        scopeStack.push(globalScope);
042    }
043
044    /**
045     * 解析所有SQL语句中的表关系。
046     * 遍历语句树,为每个表节点收集属性。
047     */
048    public void resolve() {
049        //System.out.println("==== Start resolving relations:");
050
051        for (int i = 0; i < sqlStatements.size(); i++) {
052           // System.out.println("\n==== Start SQL: "+ (i+1));
053            sqlStatements.get(i).acceptChildren(this);
054        }
055    }
056
057
058    public void postVisit(TTable table) {
059
060        switch (table.getTableType()) {
061            case join:
062                table.initAttributesForJoin();
063                break;
064            case subquery:
065                // 完成 sub-query 类型的 table 的 attributeNode 的收集,以供 attribute resolve 时使用。
066                String prefix = "";
067                if (table.getAliasClause() != null) {
068                    prefix = table.getAliasClause().toString() + ".";
069                }
070
071                table.initAttributesFromSubquery(table.getSubquery(), prefix);
072
073                TBaseType.log(String.format("Prepare attributes for subquery: %s", table.getDisplayName()), TLog.DEBUG, table.getStartToken());
074                for (TAttributeNode a : table.getAttributes()) {
075                    TBaseType.log(String.format("\tAttriubte: %s", a.getName()), TLog.DEBUG, table.getStartToken());
076                }
077                break;
078            case objectname:
079                if (table.isCTEName()) {
080                    // 这是一个指向 CTE 的 table ref,根据 CTE 生成该 table ref自己的 attribute
081                    table.initAttributesFromCTE(table.getCTE());
082                }
083                break;                
084
085        }
086    }
087
088    public void postVisit(TJoinExpr joinExpr){
089        joinExpr.initAttributes(2);
090    }
091
092    public void postVisit(TFromClause fromClause){
093        fromClause.collectAttributes();
094    }
095
096
097    public void preVisit(TCTE cte) {
098        if (cte.getColumnList() != null){
099            cte.initAttributesFromColumnList();
100        }
101    }
102
103    public void postVisit(TCTE cte) {
104        if (cte.getColumnList() == null){
105            cte.initAttributesFromSubQuery();
106        }
107    }
108
109}