001package gudusoft.gsqlparser.analyzer.v2;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.TGSqlParser;
005import gudusoft.gsqlparser.ir.builder.IBoundIRBuilder;
006import gudusoft.gsqlparser.ir.builder.IRTranslator;
007import gudusoft.gsqlparser.analyzer.v2.callgraph.CallGraph;
008import gudusoft.gsqlparser.ir.bound.BoundProgram;
009
010import java.util.List;
011
012/**
013 * Main entry point for the IR-based Analyzer v2.
014 * <p>
015 * Provides high-level APIs for analyzing SQL/PL/SQL text and producing
016 * structured analysis results (call graphs, impact analysis, lineage).
017 * <p>
018 * Phase A: Parses SQL and produces BoundProgram with routine/object/column refs.
019 * Phase B: Adds CallGraph and impact analysis.
020 * Phase C: Adds CFG/DFG and legacy diff.
021 */
022public class AnalyzerV2Facade {
023
024    private final IBoundIRBuilder boundBuilder;
025
026    public AnalyzerV2Facade(IBoundIRBuilder boundBuilder) {
027        this.boundBuilder = boundBuilder;
028    }
029
030    /**
031     * Analyzes the given SQL/PL/SQL text and returns the analysis result.
032     *
033     * @param sqlText SQL or PL/SQL text to analyze
034     * @param vendor  database vendor
035     * @param config  analyzer configuration
036     * @return analysis result
037     */
038    public AnalysisResult analyze(String sqlText, EDbVendor vendor, AnalyzerV2Config config) {
039        // Gate IR construction behind useIRPath flag
040        if (config != null && !config.useIRPath) {
041            return new AnalysisResult(new IRProgram(new BoundProgram()));
042        }
043
044        TGSqlParser parser = new TGSqlParser(vendor);
045        parser.sqltext = sqlText;
046        int result = parser.parse();
047        if (result != 0) {
048            // Return empty result on parse failure
049            return new AnalysisResult(new IRProgram(new BoundProgram()));
050        }
051
052        IRTranslator translator = new IRTranslator(config, boundBuilder);
053        IRProgram irProgram = translator.translate(parser.sqlstatements);
054
055        // Build CallGraph from BoundProgram
056        CallGraph callGraph = CallGraph.buildFrom(irProgram.getBoundProgram());
057        AnalysisResult analysisResult = new AnalysisResult(irProgram, callGraph);
058        analysisResult.setConfig(config);
059        return analysisResult;
060    }
061
062    /**
063     * Analyzes multiple SQL/PL/SQL files.
064     *
065     * @param sqlTexts list of SQL texts (one per file)
066     * @param vendor   database vendor
067     * @param config   analyzer configuration
068     * @return analysis result combining all files
069     */
070    public AnalysisResult analyzeMultiple(List<String> sqlTexts, EDbVendor vendor, AnalyzerV2Config config) {
071        // Phase A: analyze each text independently and merge bound programs
072        BoundProgram mergedProgram = new BoundProgram();
073
074        for (String sqlText : sqlTexts) {
075            TGSqlParser parser = new TGSqlParser(vendor);
076            parser.sqltext = sqlText;
077            int result = parser.parse();
078            if (result != 0) {
079                continue;
080            }
081
082            BoundProgram partial = boundBuilder.build(parser.sqlstatements, config);
083            mergeBoundPrograms(mergedProgram, partial);
084        }
085
086        CallGraph callGraph = CallGraph.buildFrom(mergedProgram);
087        return new AnalysisResult(new IRProgram(mergedProgram), callGraph);
088    }
089
090    private void mergeBoundPrograms(BoundProgram target, BoundProgram source) {
091        for (gudusoft.gsqlparser.ir.bound.BoundScope scope : source.getScopes()) {
092            target.addScope(scope);
093        }
094        for (java.util.Map.Entry<String, gudusoft.gsqlparser.ir.bound.BoundRoutineSymbol> entry
095                : source.getRoutineIndex().entrySet()) {
096            target.registerRoutine(entry.getValue());
097        }
098        for (gudusoft.gsqlparser.ir.bound.BoundObjectRef ref : source.getAllObjectRefs()) {
099            target.addObjectRef(ref);
100        }
101        for (gudusoft.gsqlparser.ir.bound.BoundColumnRef ref : source.getAllColumnRefs()) {
102            target.addColumnRef(ref);
103        }
104        for (gudusoft.gsqlparser.ir.bound.BoundRoutineRef ref : source.getAllRoutineRefs()) {
105            target.addRoutineRef(ref);
106        }
107    }
108}