001package gudusoft.gsqlparser.resolver; 002 003import gudusoft.gsqlparser.*; 004import gudusoft.gsqlparser.compiler.TContext; 005import gudusoft.gsqlparser.compiler.TScope; 006import gudusoft.gsqlparser.nodes.*; 007import gudusoft.gsqlparser.sqlenv.TSQLEnv; 008import gudusoft.gsqlparser.sqlenv.TSQLFunction; 009import gudusoft.gsqlparser.sqlenv.TSQLTable; 010import gudusoft.gsqlparser.stmt.TCreateFunctionStmt; 011import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; 012import gudusoft.gsqlparser.stmt.TSelectSqlStatement; 013 014import java.util.Stack; 015 016/** 017 * TMetadataCollector is responsible for collecting metadata information from SQL statements, 018 * particularly focusing on table and function definitions. It traverses the parse tree 019 * and builds up metadata in the global scope. 020 */ 021public class TMetadataCollector extends TParseTreeVisitor { 022 private TContext globalScope; // Stores global context including SQL environment 023 private TStatementList sqlStatements; // List of SQL statements to analyze 024 private Stack<TScope> scopeStack = new Stack<>(); // Maintains scope hierarchy 025 026 /** 027 * Constructor for TMetadataCollector. 028 * Initializes the collector with a list of SQL statements and a global context. 029 * 030 * @param sqls List of SQL statements to analyze 031 * @param context Global context that will store collected metadata 032 */ 033 public TMetadataCollector(TStatementList sqls, TContext context) { 034 this.globalScope = context; 035 sqlStatements = sqls; 036 scopeStack.push(globalScope); 037 } 038 039 /** 040 * Main method to start metadata collection process. 041 * Iterates through all SQL statements and collects metadata from each one. 042 * This includes: 043 * - Table definitions from CREATE TABLE statements 044 * - Function definitions from CREATE FUNCTION statements 045 * - Other metadata from various SQL statements 046 */ 047 public void collect() { 048 for (int i = 0; i < sqlStatements.size(); i++) { 049 sqlStatements.get(i).acceptChildren(this); 050 } 051 } 052 053 /** 054 * Processes CREATE TABLE statements to collect table metadata. 055 * Handles both regular table creation and CREATE TABLE AS SELECT. 056 * 057 * @param stmt The CREATE TABLE statement to process 058 * 059 * Actions performed: 060 * 1. Creates new table entry in SQL environment 061 * 2. Sets table name and resolves it 062 * 3. Processes column definitions 063 * 4. Handles subquery-based table creation 064 */ 065 public void preVisit(TCreateTableSqlStatement stmt) { 066 TSQLTable sqlTable = null; 067 TTable createTable = stmt.getTargetTable(); 068 if (globalScope.getSqlEnv() == null) return; 069 070 // Create new table entry 071 if (stmt.getTargetTable() != null) { 072 sqlTable = globalScope.getSqlEnv().addTable(createTable.getFullName(), true); 073 } 074 if (sqlTable == null) return; 075 createTable.setResolvedTable(sqlTable); 076 077 // Set SQL environment for table name 078 createTable.getTableName().setSqlEnv(globalScope.getSqlEnv()); 079 080 // Process columns 081 if (stmt.getColumnList().size() != 0) { 082 // Handle explicit column definitions 083 for(TColumnDefinition cd : stmt.getColumnList()) { 084 sqlTable.addColumn(cd.getColumnName().toString(), cd.getDatatype()); 085 } 086 } else if (stmt.getSubQuery() != null) { 087 // Handle CREATE TABLE AS SELECT 088 TSelectSqlStatement viewQuery = stmt.getSubQuery(); 089 if (viewQuery.isCombinedQuery()) { 090 viewQuery = viewQuery.getRightStmt(); 091 } 092 093 TResultColumnList resultColumnList = stmt.getSubQuery().getResultColumnList(); 094 if (resultColumnList != null) { 095 for (TResultColumn resultColumn : resultColumnList) { 096 if (resultColumn.getAliasNameList().size() > 0){ 097 // select t.a1, t.a2, stack(2, 'T', t.a1, t.a2, t.a3/t.a4, t.a5/t.a6, 'T+0', t.a7, t.a8, t.a9/t.a10, t.a11/t.a12) as (b1, b2, b3, b4, b5) from db1.table1 t 098 for(int j = 0; j < resultColumn.getAliasNameList().size(); j++){ 099 TObjectName column = resultColumn.getAliasNameList().get(j); 100 sqlTable.addColumn(TSQLEnv.getObjectName( TBaseType.removeQuoteChar(column.toString()))); 101 createTable.getLinkedColumns().addObjectName(column); // for getTableColumn work correctly 102 } 103 104 }else{ 105 sqlTable.addColumn(TSQLEnv.getObjectName(resultColumn.getDisplayName())); 106 } 107 108 } 109 } 110 } 111 } 112 113 /** 114 * Processes CREATE FUNCTION statements to collect function metadata. 115 * Captures function name, parameters, and return type information. 116 * 117 * @param stmt The CREATE FUNCTION statement to process 118 * 119 * Actions performed: 120 * 1. Creates new function entry in SQL environment 121 * 2. Processes function parameters 122 * 3. Sets function return type 123 */ 124 public void preVisit(TCreateFunctionStmt stmt) { 125 if (globalScope.getSqlEnv() == null) return; 126 127 // Create new function entry 128 TSQLFunction sqlFunction = globalScope.getSqlEnv().addFunction(stmt.getFunctionName().toString(), true); 129 if (sqlFunction == null) return; 130 if (stmt.getParameterDeclarations() == null) return; 131 132 // Process function parameters 133 int c = 0; 134 for(TParameterDeclaration p : stmt.getParameterDeclarations()) { 135 if (p.getParameterName() != null) { 136 sqlFunction.addParameter(c, p.getDataType(), p.getParameterName().toString()); 137 } else { 138 sqlFunction.addParameter(c, p.getDataType()); 139 } 140 } 141 142 // Set function return type 143 sqlFunction.setReturnType(stmt.getReturnDataType()); 144 } 145}