001package gudusoft.gsqlparser.dlineage.dynamicsql; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.List; 006 007/** 008 * Top-level result of {@code DataFlowAnalyzer.resolveDynamicSqlLineage}: one 009 * {@link DynamicSiteResult} per dynamic-SQL EXEC site discovered in the 010 * procedure, plus convenience views over the resolved edges and the unresolved 011 * sites. 012 */ 013public final class DynamicLineageResult { 014 015 private final String sourceProc; 016 private final String bindingHash; 017 private final List<DynamicSiteResult> sites = new ArrayList<DynamicSiteResult>(); 018 019 DynamicLineageResult(String sourceProc, String bindingHash) { 020 this.sourceProc = sourceProc; 021 this.bindingHash = bindingHash; 022 } 023 024 void addSite(DynamicSiteResult site) { 025 sites.add(site); 026 } 027 028 public String getSourceProc() { 029 return sourceProc; 030 } 031 032 public String getBindingHash() { 033 return bindingHash; 034 } 035 036 public List<DynamicSiteResult> getSites() { 037 return Collections.unmodifiableList(sites); 038 } 039 040 /** All lineage edges across all resolved sites. */ 041 public List<DynamicLineageEdge> getAllEdges() { 042 List<DynamicLineageEdge> all = new ArrayList<DynamicLineageEdge>(); 043 for (DynamicSiteResult s : sites) { 044 all.addAll(s.getEdges()); 045 } 046 return all; 047 } 048 049 /** Projected (data) lineage edges only — dlineage {@code fdd}, excluding join/filter influence. */ 050 public List<DynamicLineageEdge> getProjectedEdges() { 051 List<DynamicLineageEdge> all = new ArrayList<DynamicLineageEdge>(); 052 for (DynamicSiteResult s : sites) { 053 for (DynamicLineageEdge e : s.getEdges()) { 054 if (e.isProjectedData()) { 055 all.add(e); 056 } 057 } 058 } 059 return all; 060 } 061 062 /** Sites that could not be reduced — keep as honest diagnostics, do not guess. */ 063 public List<DynamicSiteResult> getUnresolvedSites() { 064 List<DynamicSiteResult> out = new ArrayList<DynamicSiteResult>(); 065 for (DynamicSiteResult s : sites) { 066 if (!s.isResolved()) { 067 out.add(s); 068 } 069 } 070 return out; 071 } 072 073 public boolean hasResolvedLineage() { 074 for (DynamicSiteResult s : sites) { 075 if (s.isResolved() && !s.getEdges().isEmpty()) { 076 return true; 077 } 078 } 079 return false; 080 } 081 082 @Override 083 public String toString() { 084 return "DynamicLineageResult{proc=" + sourceProc + ", sites=" + sites.size() 085 + ", edges=" + getAllEdges().size() + "}"; 086 } 087}