001package gudusoft.gsqlparser.ir.builder.postgresql;
002
003import gudusoft.gsqlparser.TCustomSqlStatement;
004import gudusoft.gsqlparser.TStatementList;
005import gudusoft.gsqlparser.analyzer.v2.AnalyzerV2Config;
006import gudusoft.gsqlparser.ir.bound.BoundProgram;
007import gudusoft.gsqlparser.ir.bound.BoundScope;
008import gudusoft.gsqlparser.ir.bound.EScopeKind;
009import gudusoft.gsqlparser.ir.builder.IBoundIRBuilder;
010
011import java.util.Arrays;
012import java.util.List;
013
014/**
015 * PostgreSQL PL/pgSQL implementation of {@link IBoundIRBuilder}.
016 * <p>
017 * Orchestrates three internal phases:
018 * <ol>
019 *   <li>Create global scope</li>
020 *   <li>Run {@link PostgresqlSymbolCollector} (visitor) to extract
021 *       routines, variables, table refs, and call refs</li>
022 *   <li>Run {@link PostgresqlRoutineRefResolver} with search_path
023 *       to match refs to symbols</li>
024 * </ol>
025 */
026public class PostgresqlBoundIRBuilder implements IBoundIRBuilder {
027
028    private final List<String> searchPath;
029
030    public PostgresqlBoundIRBuilder() {
031        this(Arrays.asList("public"));
032    }
033
034    public PostgresqlBoundIRBuilder(List<String> searchPath) {
035        this.searchPath = searchPath;
036    }
037
038    @Override
039    public BoundProgram build(TStatementList stmts, AnalyzerV2Config config) {
040        return build(stmts, config, "");
041    }
042
043    public BoundProgram build(TStatementList stmts, AnalyzerV2Config config, String fileId) {
044        BoundProgram program = new BoundProgram();
045
046        BoundScope globalScope = new BoundScope(EScopeKind.GLOBAL, null, null);
047        program.addScope(globalScope);
048
049        if (stmts == null || stmts.size() == 0) {
050            return program;
051        }
052
053        // Phase 2: Walk AST
054        PostgresqlSymbolCollector collector =
055                new PostgresqlSymbolCollector(program, globalScope, config, fileId, searchPath);
056        for (int i = 0; i < stmts.size(); i++) {
057            TCustomSqlStatement stmt = stmts.get(i);
058            if (stmt != null) {
059                stmt.acceptChildren(collector);
060            }
061        }
062
063        // Phase 3: Resolve routine references
064        PostgresqlRoutineRefResolver resolver = new PostgresqlRoutineRefResolver(searchPath);
065        resolver.resolve(program);
066
067        return program;
068    }
069}