001package gudusoft.gsqlparser.resolver2.model; 002 003import gudusoft.gsqlparser.nodes.TObjectName; 004import gudusoft.gsqlparser.nodes.TTable; 005import gudusoft.gsqlparser.resolver2.matcher.INameMatcher; 006import gudusoft.gsqlparser.resolver2.matcher.DefaultNameMatcher; 007 008import java.util.*; 009 010/** 011 * Global context for resolution results. 012 * Provides efficient querying and statistics about resolved columns. 013 * 014 * Design principles: 015 * 1. Reverse indexing for O(1) queries 016 * 2. Categorized storage for quick access to different resolution states 017 * 3. Statistics for monitoring resolution quality 018 */ 019public class ResolutionContext { 020 021 // === Core storage: forward mapping === 022 023 /** All processed column references -> resolution results */ 024 private final Map<TObjectName, ResolutionResult> resolutions = new LinkedHashMap<>(); 025 026 // === Reverse indexes for efficient queries === 027 028 /** Table -> all columns referencing that table */ 029 private final Map<TTable, List<TObjectName>> tableReferences = new HashMap<>(); 030 031 /** Column name -> all column references with that name (for conflict detection) */ 032 private final Map<String, List<TObjectName>> columnNameIndex = new HashMap<>(); 033 034 // === Categorized lists for quick access === 035 036 /** Exactly matched columns (EXACT_MATCH) */ 037 private final List<TObjectName> exactMatches = new ArrayList<>(); 038 039 /** Ambiguous columns (AMBIGUOUS) */ 040 private final List<TObjectName> ambiguousColumns = new ArrayList<>(); 041 042 /** Unresolved columns (NOT_FOUND) */ 043 private final List<TObjectName> unresolvedColumns = new ArrayList<>(); 044 045 // === Statistics === 046 047 /** Table reference counts */ 048 private final Map<TTable, Integer> tableReferenceCounts = new HashMap<>(); 049 050 /** Total column references processed */ 051 private int totalColumnReferences = 0; 052 053 054 // ===== Internal methods: called by NameResolver ===== 055 056 /** 057 * Register a resolution result. 058 * Called by NameResolver when a column is resolved. 059 */ 060 public void registerResolution(TObjectName objName, ResolutionResult result) { 061 // 1. Forward storage 062 resolutions.put(objName, result); 063 totalColumnReferences++; 064 065 // 2. Update reverse index by column name 066 String columnName = objName.getColumnNameOnly(); 067 if (columnName != null) { 068 columnNameIndex.computeIfAbsent(columnName, k -> new ArrayList<>()) 069 .add(objName); 070 } 071 072 // 3. Categorize by status 073 switch (result.getStatus()) { 074 case EXACT_MATCH: 075 exactMatches.add(objName); 076 ColumnSource source = result.getColumnSource(); 077 if (source != null) { 078 updateTableReference(source.getFinalTable(), objName); 079 } 080 break; 081 082 case AMBIGUOUS: 083 ambiguousColumns.add(objName); 084 // For ambiguous: all candidates count as references 085 AmbiguousColumnSource ambiguous = result.getAmbiguousSource(); 086 if (ambiguous != null) { 087 for (ColumnSource candidate : ambiguous.getCandidates()) { 088 updateTableReference(candidate.getFinalTable(), objName); 089 } 090 } 091 break; 092 093 case NOT_FOUND: 094 unresolvedColumns.add(objName); 095 break; 096 } 097 } 098 099 /** 100 * Update table reference index 101 */ 102 private void updateTableReference(TTable table, TObjectName objName) { 103 if (table == null) return; 104 105 // Reverse index 106 tableReferences.computeIfAbsent(table, k -> new ArrayList<>()) 107 .add(objName); 108 109 // Reference count 110 tableReferenceCounts.merge(table, 1, Integer::sum); 111 } 112 113 114 // ===== Public query API (Level 2 API) ===== 115 116 /** 117 * Get all column references to a specific table. 118 * Complexity: O(1) 119 * 120 * @param table Target table 121 * @return List of TObjectName referencing that table 122 */ 123 public List<TObjectName> getReferencesTo(TTable table) { 124 return tableReferences.getOrDefault(table, Collections.emptyList()); 125 } 126 127 /** 128 * Get all column references to a specific table.column. 129 * Complexity: O(m) where m = number of references to the table 130 * 131 * @param table Target table 132 * @param columnName Target column name 133 * @return List of matching TObjectName 134 */ 135 public List<TObjectName> getReferencesTo(TTable table, String columnName) { 136 INameMatcher matcher = new DefaultNameMatcher(); 137 138 return getReferencesTo(table).stream() 139 .filter(obj -> { 140 String colName = obj.getColumnNameOnly(); 141 return colName != null && matcher.matches(colName, columnName); 142 }) 143 .collect(java.util.stream.Collectors.toList()); 144 } 145 146 /** 147 * Find all column references with a given name (for conflict detection). 148 * Complexity: O(1) 149 */ 150 public List<TObjectName> getColumnsByName(String columnName) { 151 return columnNameIndex.getOrDefault(columnName, Collections.emptyList()); 152 } 153 154 /** 155 * Get all exactly matched columns 156 */ 157 public List<TObjectName> getExactMatches() { 158 return Collections.unmodifiableList(exactMatches); 159 } 160 161 /** 162 * Get all ambiguous columns 163 */ 164 public List<TObjectName> getAmbiguousColumns() { 165 return Collections.unmodifiableList(ambiguousColumns); 166 } 167 168 /** 169 * Get all unresolved columns 170 */ 171 public List<TObjectName> getUnresolvedColumns() { 172 return Collections.unmodifiableList(unresolvedColumns); 173 } 174 175 /** 176 * Get reference count for a specific table 177 */ 178 public int getTableReferenceCount(TTable table) { 179 return tableReferenceCounts.getOrDefault(table, 0); 180 } 181 182 /** 183 * Get all tables that have been referenced 184 */ 185 public Set<TTable> getAllReferencedTables() { 186 return tableReferences.keySet(); 187 } 188 189 /** 190 * Get resolution statistics 191 */ 192 public ResolutionStatistics getStatistics() { 193 return new ResolutionStatistics( 194 totalColumnReferences, 195 exactMatches.size(), 196 ambiguousColumns.size(), 197 unresolvedColumns.size(), 198 tableReferences.size() 199 ); 200 } 201 202 /** 203 * Get resolution result for a specific TObjectName 204 */ 205 public ResolutionResult getResolution(TObjectName objName) { 206 return resolutions.get(objName); 207 } 208 209 /** 210 * Clear all data (for reuse or testing) 211 */ 212 public void clear() { 213 resolutions.clear(); 214 tableReferences.clear(); 215 columnNameIndex.clear(); 216 exactMatches.clear(); 217 ambiguousColumns.clear(); 218 unresolvedColumns.clear(); 219 tableReferenceCounts.clear(); 220 totalColumnReferences = 0; 221 } 222}