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}