001package gudusoft.gsqlparser.parser;
002
003import gudusoft.gsqlparser.EDbVendor;
004
005/**
006 * Strategy interface for vendor-specific SQL parsing.
007 *
008 * <p>This interface defines the contract for all database vendor-specific parsers.
009 * Each vendor (Oracle, MySQL, PostgreSQL, etc.) provides its own implementation
010 * that handles the vendor-specific tokenization, parsing, and semantic analysis.
011 *
012 * <p><b>Design Pattern:</b> Strategy Pattern
013 * <ul>
014 *   <li>The strategy (SqlParser) is selected at runtime based on database vendor</li>
015 *   <li>All inputs come from {@link ParserContext} (immutable)</li>
016 *   <li>All outputs go to {@link SqlParseResult} (immutable)</li>
017 * </ul>
018 *
019 * <p><b>Usage Example:</b>
020 * <pre>
021 * // Get parser for specific vendor
022 * SqlParser parser = SqlParserFactory.get(EDbVendor.dbvoracle);
023 *
024 * // Build context with inputs
025 * ParserContext context = new ParserContext.Builder(EDbVendor.dbvoracle)
026 *     .sqlText("SELECT * FROM employees")
027 *     .build();
028 *
029 * // Parse and get result
030 * SqlParseResult result = parser.parse(context);
031 *
032 * // Access outputs
033 * TStatementList statements = result.getSqlStatements();
034 * </pre>
035 *
036 * @see ParserContext
037 * @see SqlParseResult
038 * @see AbstractSqlParser
039 * @since 3.2.0.0
040 */
041public interface SqlParser {
042
043    /**
044     * Get the database vendor this parser handles.
045     *
046     * @return the database vendor (e.g., dbvoracle, dbvmysql)
047     */
048    EDbVendor getVendor();
049
050    /**
051     * Parse SQL from the given context.
052     *
053     * <p>This method performs full parsing including:
054     * <ul>
055     *   <li>Tokenization (lexical analysis)</li>
056     *   <li>Syntax analysis (building parse tree)</li>
057     *   <li>Semantic analysis (resolving references)</li>
058     * </ul>
059     *
060     * <p>All inputs come from the context parameter, all outputs go to the result.
061     * This ensures clean separation of concerns and thread-safety.
062     *
063     * @param context immutable context containing all parser inputs
064     *                (SQL text, options, callbacks, etc.)
065     * @return immutable result containing all parser outputs
066     *         (statements, tokens, errors, etc.)
067     */
068    SqlParseResult parse(ParserContext context);
069
070    /**
071     * Tokenize SQL without parsing or statement extraction.
072     *
073     * <p>This method performs only tokenization (lexical analysis):
074     * <ul>
075     *   <li>Tokenization (lexical analysis)</li>
076     * </ul>
077     *
078     * <p>The result contains tokens but NO statements. Use this when you only
079     * need the token stream (e.g., for syntax highlighting, token analysis).
080     *
081     * <p>For statement boundaries without full parsing, use {@link #getrawsqlstatements(ParserContext)}.
082     *
083     * @param context immutable context containing all parser inputs
084     * @return immutable result containing tokens only (no statements)
085     */
086    SqlParseResult tokenize(ParserContext context);
087
088    /**
089     * Vendor policy validation, run by {@code TGSqlParser} AFTER every statement
090     * has been parsed ("recognize then reject", Sybase family decomposition).
091     *
092     * <p>Runs post-parse on purpose: some statement objects are REPLACED during
093     * parsing (the refined statement is built from the parse-tree node), so an
094     * error attached at raw-extraction time can silently vanish with the old
095     * object. Post-parse, the statements are final.
096     *
097     * <p>Default is a no-op returning {@code null} — behaviour of every vendor
098     * that does not override this is untouched.
099     *
100     * @param statements the fully parsed statement list
101     * @return statements this vendor rejects (errors already attached), or null
102     */
103    default java.util.List<gudusoft.gsqlparser.TCustomSqlStatement>
104            validateRecognizedStatements(gudusoft.gsqlparser.TStatementList statements) {
105        return null;
106    }
107
108    /**
109     * Extract raw SQL statements without full parsing.
110     *
111     * <p>This method performs:
112     * <ul>
113     *   <li>Tokenization (lexical analysis)</li>
114     *   <li>Raw statement extraction (statement boundary detection)</li>
115     * </ul>
116     *
117     * <p>This is faster than {@link #parse(ParserContext)} because it skips
118     * detailed syntax checking and semantic analysis. The statements returned
119     * have their tokens grouped correctly but no AST (parse tree) is built.
120     *
121     * <p><b>Use cases:</b>
122     * <ul>
123     *   <li>Split a script into individual statements</li>
124     *   <li>Determine statement types without full parsing</li>
125     *   <li>Quick validation of statement boundaries</li>
126     *   <li>Pre-processing before selective parsing</li>
127     * </ul>
128     *
129     * <p><b>Equivalent to legacy API:</b> {@code TGSqlParser.getrawsqlstatements()}
130     *
131     * <p><b>Default implementation:</b> For parsers still in delegation phase,
132     * this default implementation falls back to {@link #tokenize(ParserContext)}.
133     * Parsers extending AbstractSqlParser override this with proper implementation.
134     *
135     * @param context immutable context containing all parser inputs
136     * @return immutable result containing tokens and raw statements (no AST)
137     */
138    default SqlParseResult getrawsqlstatements(ParserContext context) {
139        // Default implementation for parsers in delegation phase
140        // Just tokenize - subclasses should override with proper implementation
141        return tokenize(context);
142    }
143
144    /**
145     * Extract raw statements from already-tokenized source without re-tokenization.
146     *
147     * <p>This method is used when tokens are already available from a previous
148     * tokenization step (e.g., via {@code dosqltexttotokenlist()}). It performs
149     * only raw statement extraction without repeating tokenization.
150     *
151     * <p><b>Default implementation:</b> Falls back to tokenize() method for vendors
152     * that haven't implemented this optimization yet.
153     *
154     * @param context immutable context containing all parser inputs
155     * @param tokens already-tokenized source token list
156     * @return statement list containing extracted raw statements
157     * @since 3.2.0.0
158     * @deprecated As of 3.2.0.0, replaced by {@link #getrawsqlstatements(ParserContext)}
159     *             which returns a richer {@link SqlParseResult} object containing statements,
160     *             tokens, errors, timing information, and more. This method only returns
161     *             {@link gudusoft.gsqlparser.TStatementList} without error information.
162     *             <p>
163     *             <b>Migration:</b> Use {@code vendorParser.getrawsqlstatements(context)}
164     *             instead, which performs both tokenization and extraction in a single call
165     *             and returns complete result information via {@link SqlParseResult}.
166     *             <p>
167     *             This method will be removed in a future major version.
168     */
169    @Deprecated
170    default gudusoft.gsqlparser.TStatementList doExtractRawStatements(ParserContext context, gudusoft.gsqlparser.TSourceTokenList tokens) {
171        // Default implementation: fall back to tokenize() which does both tokenization and extraction
172        // Vendors that extend AbstractSqlParser will override this via the doExtractRawStatements() implementation
173//        SqlParseResult result = tokenize(context);
174//        return result.getSqlStatements();
175        return null; // To be implemented by vendors, this method must be orerridden
176    }
177}