001package gudusoft.gsqlparser.parser;
002
003import gudusoft.gsqlparser.EDbVendor;
004import gudusoft.gsqlparser.TBaseType;
005import gudusoft.gsqlparser.TCustomLexer;
006import gudusoft.gsqlparser.TCustomParser;
007import gudusoft.gsqlparser.TCustomSqlStatement;
008import gudusoft.gsqlparser.TLexerOdbc;
009import gudusoft.gsqlparser.TParserOdbc;
010import gudusoft.gsqlparser.TSourceToken;
011import gudusoft.gsqlparser.TSourceTokenList;
012import gudusoft.gsqlparser.TStatementList;
013import gudusoft.gsqlparser.TSyntaxError;
014import gudusoft.gsqlparser.EFindSqlStateType;
015import gudusoft.gsqlparser.ETokenType;
016import gudusoft.gsqlparser.ETokenStatus;
017import gudusoft.gsqlparser.ESqlStatementType;
018import gudusoft.gsqlparser.EErrorType;
019import gudusoft.gsqlparser.stmt.TUnknownSqlStatement;
020import gudusoft.gsqlparser.stmt.mssql.TMssqlBlock;
021import gudusoft.gsqlparser.stmt.mssql.TMssqlExecute;
022import gudusoft.gsqlparser.sqlcmds.ISqlCmds;
023import gudusoft.gsqlparser.sqlcmds.SqlCmdsFactory;
024import gudusoft.gsqlparser.compiler.TContext;
025import gudusoft.gsqlparser.sqlenv.TSQLEnv;
026import gudusoft.gsqlparser.compiler.TGlobalScope;
027import gudusoft.gsqlparser.compiler.TFrame;
028import gudusoft.gsqlparser.resolver.TSQLResolver;
029import gudusoft.gsqlparser.TLog;
030import gudusoft.gsqlparser.compiler.TASTEvaluator;
031
032import java.io.BufferedReader;
033import java.util.ArrayList;
034import java.util.List;
035import java.util.Stack;
036
037import static gudusoft.gsqlparser.ESqlStatementType.sstmssqlreturn;
038
039/**
040 * ODBC database SQL parser implementation.
041 *
042 * <p>This parser handles ODBC-specific SQL syntax including:
043 * <ul>
044 *   <li>ODBC escape sequences ({ ... })</li>
045 *   <li>ODBC date/time literals ({ d 'date' }, { t 'time' }, { ts 'timestamp' })</li>
046 *   <li>ODBC function calls ({ fn function_name(...) })</li>
047 *   <li>ODBC outer join syntax ({ oj outer_join })</li>
048 *   <li>ODBC CALL statements ({ call procedure_name(...) })</li>
049 *   <li>Base MSSQL syntax (inherited)</li>
050 * </ul>
051 *
052 * <p><b>Design Notes:</b>
053 * <ul>
054 *   <li>Extends {@link AbstractSqlParser} using the template method pattern</li>
055 *   <li>Uses {@link TLexerOdbc} for tokenization</li>
056 *   <li>Uses {@link TParserOdbc} for parsing</li>
057 *   <li>Based on MSSQL parser with ODBC escape sequence handling</li>
058 *   <li>Delimiter character: ';' for SQL statements</li>
059 * </ul>
060 *
061 * <p><b>Usage Example:</b>
062 * <pre>
063 * // Get ODBC parser from factory
064 * SqlParser parser = SqlParserFactory.get(EDbVendor.dbvodbc);
065 *
066 * // Build context
067 * ParserContext context = new ParserContext.Builder(EDbVendor.dbvodbc)
068 *     .sqlText("SELECT * FROM Employees WHERE hire_date > { d '2020-01-01' }")
069 *     .build();
070 *
071 * // Parse
072 * SqlParseResult result = parser.parse(context);
073 *
074 * // Access statements
075 * TStatementList statements = result.getSqlStatements();
076 * </pre>
077 *
078 * @see SqlParser
079 * @see AbstractSqlParser
080 * @see TLexerOdbc
081 * @see TParserOdbc
082 * @since 3.3.0.0
083 */
084public class OdbcSqlParser extends AbstractSqlParser {
085
086    /**
087     * Construct ODBC SQL parser.
088     * <p>
089     * Configures the parser for ODBC database with default delimiter (;).
090     * <p>
091     * Following the original TGSqlParser pattern, the lexer and parser are
092     * created once in the constructor and reused for all parsing operations.
093     */
094    public OdbcSqlParser() {
095        super(EDbVendor.dbvodbc);
096        this.delimiterChar = ';';
097        this.defaultDelimiterStr = ";";
098
099        // Create lexer once - will be reused for all parsing operations
100        this.flexer = new TLexerOdbc();
101        this.flexer.delimiterchar = this.delimiterChar;
102        this.flexer.defaultDelimiterStr = this.defaultDelimiterStr;
103
104        // Set parent's lexer reference for shared tokenization logic
105        this.lexer = this.flexer;
106
107        // Create parser once - will be reused for all parsing operations
108        this.fparser = new TParserOdbc(null);
109        this.fparser.lexer = this.flexer;
110    }
111
112    // ========== Parser Components ==========
113
114    /** The ODBC lexer used for tokenization */
115    public TLexerOdbc flexer;
116
117    /** SQL parser (for ODBC statements) */
118    private TParserOdbc fparser;
119
120    /** Current statement being built during extraction */
121    private TCustomSqlStatement gcurrentsqlstatement;
122
123    // Note: Global context and frame stack fields inherited from AbstractSqlParser:
124    // - protected TContext globalContext
125    // - protected TSQLEnv sqlEnv
126    // - protected Stack<TFrame> frameStack
127    // - protected TFrame globalFrame
128
129    // ========== AbstractSqlParser Abstract Methods Implementation ==========
130
131    /**
132     * Return the ODBC lexer instance.
133     */
134    @Override
135    protected TCustomLexer getLexer(ParserContext context) {
136        return this.flexer;
137    }
138
139    /**
140     * Return the ODBC SQL parser instance with updated token list.
141     */
142    @Override
143    protected TCustomParser getParser(ParserContext context, TSourceTokenList tokens) {
144        this.fparser.sourcetokenlist = tokens;
145        return this.fparser;
146    }
147
148    /**
149     * Call ODBC-specific tokenization logic.
150     * <p>
151     * Delegates to doodbcsqltexttotokenlist which handles ODBC's
152     * specific escape sequences and MSSQL base syntax.
153     */
154    @Override
155    protected void tokenizeVendorSql() {
156        doodbcsqltexttotokenlist();
157    }
158
159    /**
160     * Setup ODBC parser for raw statement extraction.
161     * <p>
162     * ODBC uses a single parser, so we inject sqlcmds and update
163     * the token list for the main parser only.
164     */
165    @Override
166    protected void setupVendorParsersForExtraction() {
167        // Inject sqlcmds into parser (required for make_stmt)
168        this.fparser.sqlcmds = this.sqlcmds;
169
170        // Update token list for parser
171        this.fparser.sourcetokenlist = this.sourcetokenlist;
172    }
173
174    /**
175     * Call ODBC-specific raw statement extraction logic.
176     * <p>
177     * Delegates to doodbcgetrawsqlstatements which handles ODBC's
178     * statement delimiters (inherits from MSSQL: semicolon and GO command).
179     */
180    @Override
181    protected void extractVendorRawStatements(SqlParseResult.Builder builder) {
182        doodbcgetrawsqlstatements(builder);
183    }
184
185    /**
186     * Perform full parsing of statements with syntax checking.
187     * <p>
188     * This method orchestrates the parsing of all statements.
189     */
190    @Override
191    protected TStatementList performParsing(ParserContext context,
192                                           TCustomParser parser,
193                                           TCustomParser secondaryParser,
194                                           TSourceTokenList tokens,
195                                           TStatementList rawStatements) {
196        // Store references
197        this.fparser = (TParserOdbc) parser;
198        this.sourcetokenlist = tokens;
199        this.parserContext = context;
200
201        // Use the raw statements passed from AbstractSqlParser.parse()
202        this.sqlstatements = rawStatements;
203
204        // Initialize statement parsing infrastructure
205        this.sqlcmds = SqlCmdsFactory.get(vendor);
206
207        // Inject sqlcmds into parser (required for make_stmt and other methods)
208        this.fparser.sqlcmds = this.sqlcmds;
209
210        // Initialize global context for semantic analysis
211        initializeGlobalContext();
212
213        // Parse each statement with exception handling for robustness
214        for (int i = 0; i < sqlstatements.size(); i++) {
215            TCustomSqlStatement stmt = sqlstatements.getRawSql(i);
216
217            try {
218                stmt.setFrameStack(frameStack);
219
220                // Parse the statement
221                int parseResult = stmt.parsestatement(null, false, context.isOnlyNeedRawParseTree());
222
223                // Handle error recovery for CREATE TABLE/INDEX
224                boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE;
225                if (doRecover && ((parseResult != 0) || (stmt.getErrorCount() > 0))) {
226                    handleCreateTableErrorRecovery(stmt);
227                }
228
229                // Collect syntax errors
230                if ((parseResult != 0) || (stmt.getErrorCount() > 0)) {
231                    copyErrorsFromStatement(stmt);
232                }
233
234            } catch (Exception ex) {
235                // Use inherited exception handler from AbstractSqlParser
236                // This provides consistent error handling across all database parsers
237                handleStatementParsingException(stmt, i, ex);
238                continue;
239            }
240        }
241
242        // Clean up frame stack
243        if (globalFrame != null) {
244            globalFrame.popMeFromStack(frameStack);
245        }
246
247        return this.sqlstatements;
248    }
249
250    // Note: initializeGlobalContext() inherited from AbstractSqlParser
251    // Note: No override of afterStatementParsed() needed - default (no-op) is appropriate for ODBC
252
253    /**
254     * Handle error recovery for CREATE TABLE/INDEX statements.
255     */
256    private void handleCreateTableErrorRecovery(TCustomSqlStatement stmt) {
257        if (((stmt.sqlstatementtype == ESqlStatementType.sstcreatetable)
258                || (stmt.sqlstatementtype == ESqlStatementType.sstcreateindex))
259                && (!TBaseType.c_createTableStrictParsing)) {
260
261            int nested = 0;
262            boolean isIgnore = false, isFoundIgnoreToken = false;
263            TSourceToken firstIgnoreToken = null;
264
265            for (int k = 0; k < stmt.sourcetokenlist.size(); k++) {
266                TSourceToken st = stmt.sourcetokenlist.get(k);
267                if (isIgnore) {
268                    if (st.issolidtoken() && (st.tokencode != ';')) {
269                        isFoundIgnoreToken = true;
270                        if (firstIgnoreToken == null) {
271                            firstIgnoreToken = st;
272                        }
273                    }
274                    if (st.tokencode != ';') {
275                        st.tokencode = TBaseType.sqlpluscmd;
276                    }
277                    continue;
278                }
279                if (st.tokencode == (int) ')') {
280                    nested--;
281                    if (nested == 0) {
282                        boolean isSelect = false;
283                        TSourceToken st1 = st.searchToken(TBaseType.rrw_as, 1);
284                        if (st1 != null) {
285                            TSourceToken st2 = st.searchToken((int) '(', 2);
286                            if (st2 != null) {
287                                TSourceToken st3 = st.searchToken(TBaseType.rrw_select, 3);
288                                isSelect = (st3 != null);
289                            }
290                        }
291                        if (!isSelect) isIgnore = true;
292                    }
293                } else if (st.tokencode == (int) '(') {
294                    nested++;
295                }
296            }
297
298            if (isFoundIgnoreToken) {
299                stmt.clearError();
300                stmt.parsestatement(null, false);
301            }
302        }
303    }
304
305    /**
306     * Perform ODBC-specific semantic analysis using TSQLResolver.
307     */
308    @Override
309    protected void performSemanticAnalysis(ParserContext context, TStatementList statements) {
310        if (TBaseType.isEnableResolver() && getSyntaxErrors().isEmpty()) {
311            TSQLResolver resolver = new TSQLResolver(globalContext, statements);
312            resolver.resolve();
313        }
314    }
315
316    /**
317     * Perform interpretation/evaluation on parsed statements.
318     */
319    @Override
320    protected void performInterpreter(ParserContext context, TStatementList statements) {
321        if (TBaseType.ENABLE_INTERPRETER && getSyntaxErrors().isEmpty()) {
322            TLog.clearLogs();
323            TGlobalScope interpreterScope = new TGlobalScope(sqlEnv);
324            TLog.enableInterpreterLogOnly();
325            TASTEvaluator astEvaluator = new TASTEvaluator(statements, interpreterScope);
326            astEvaluator.eval();
327        }
328    }
329
330    // ========== ODBC-Specific Tokenization ==========
331
332    /**
333     * ODBC-specific tokenization logic.
334     * <p>
335     * Extracted from: TGSqlParser.doodbcsqltexttotokenlist() (lines 4119-4148)
336     * <p>
337     * This method first performs MSSQL tokenization, then post-processes
338     * the token list to handle ODBC escape sequences:
339     * <ul>
340     *   <li>{ d 'date' } - ODBC date literal</li>
341     *   <li>{ t 'time' } - ODBC time literal</li>
342     *   <li>{ ts 'timestamp' } - ODBC timestamp literal</li>
343     *   <li>{ fn function(...) } - ODBC function call</li>
344     *   <li>{ oj outer_join } - ODBC outer join</li>
345     *   <li>{ call procedure(...) } - ODBC procedure call</li>
346     * </ul>
347     */
348    private void doodbcsqltexttotokenlist() {
349        boolean insideODBC = false;
350        TSourceToken odbcPrefix = null;
351
352        // First, perform MSSQL tokenization
353        domssqlsqltexttotokenlist();
354
355        // Then post-process for ODBC escape sequences
356        for (int i = 0; i < sourcetokenlist.size(); i++) {
357            TSourceToken ast = sourcetokenlist.get(i);
358
359            // Entering ODBC escape sequence
360            if ((ast.tokencode == '{') || (ast.tokencode == TBaseType.odbc_esc_prefix)) {
361                insideODBC = true;
362                odbcPrefix = ast;
363            }
364
365            // Exiting ODBC escape sequence
366            if ((ast.tokencode == '}') || (ast.tokencode == TBaseType.odbc_esc_terminator)) {
367                insideODBC = false;
368                odbcPrefix = null;
369            }
370
371            // Convert ODBC keywords to identifiers when NOT inside ODBC blocks
372            if (((ast.tokencode == TBaseType.rrw_odbc_d)
373                    || (ast.tokencode == TBaseType.rrw_odbc_t)
374                    || (ast.tokencode == TBaseType.rrw_odbc_ts)
375                    || (ast.tokencode == TBaseType.rrw_odbc_fn)
376                    || (ast.tokencode == TBaseType.rrw_odbc_oj)
377                ) && (!insideODBC)) {
378                ast.tokencode = TBaseType.ident;
379            }
380
381            // Link CALL statements to ODBC prefix when inside ODBC blocks
382            if ((ast.tokencode == TBaseType.rrw_call) && (insideODBC)) {
383                odbcPrefix.setLinkToken(ast);
384            }
385        }
386    }
387
388    /**
389     * MSSQL-specific tokenization logic (inherited behavior).
390     * <p>
391     * This is the base tokenization used by ODBC before ODBC-specific
392     * post-processing.
393     */
394    private void domssqlsqltexttotokenlist() {
395        TSourceToken lcprevtoken = null;
396        int lcsteps = 0;
397        TSourceToken asourcetoken, lctoken, lctoken2, lctoken3;
398        int yychar;
399        boolean iskeywordgo;
400
401        asourcetoken = getanewsourcetoken();
402
403        if (asourcetoken == null) return;
404
405        yychar = asourcetoken.tokencode;
406
407        boolean lcinopenrowset = false;
408        int lcnested = 0;
409
410        while (yychar > 0) {
411
412            if (asourcetoken.tokencode == TBaseType.rrw_openrowset) {
413                // openrowset(....)
414                lcinopenrowset = true;
415                lcnested = 0;
416            } else if (asourcetoken.tokentype == ETokenType.ttleftparenthesis) {
417                if ((lcsteps > 0) && TBaseType.assigned(lcprevtoken)) {
418                    if (lcprevtoken.tokencode == TBaseType.rrw_primary) {
419                        lcprevtoken.tokencode = TBaseType.rrw_select - 2;  //rw_primary2
420                        checkconstarinttoken(lcprevtoken);
421                    } else if (lcprevtoken.tokencode == TBaseType.rrw_foreign) {
422                        lcprevtoken.tokencode = TBaseType.rrw_select - 4;  //rw_foreign2
423                        checkconstarinttoken(lcprevtoken);
424                    } else if (lcprevtoken.tokencode == TBaseType.rrw_unique) {
425                        lcprevtoken.tokencode = TBaseType.rrw_select - 1;  //rw_unique2
426                        checkconstarinttoken(lcprevtoken);
427                    }
428                    lcprevtoken = null;
429                    lcsteps = 0;
430                }
431
432                // openrowset(....)
433                if (lcinopenrowset)
434                    lcnested++;
435            } else if (asourcetoken.tokentype == ETokenType.ttrightparenthesis) {
436                // openrowset(....)
437                if (lcinopenrowset) {
438                    if ((lcnested > 0))
439                        lcnested--;
440                    if (lcnested == 0)
441                        lcinopenrowset = false;
442                }
443            } else if (asourcetoken.tokentype == ETokenType.ttsemicolon) {
444                if (lcinopenrowset) {
445                    asourcetoken.tokentype = ETokenType.ttsemicolon2;
446                } else {
447                    lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin, -1);
448                    if (lctoken2 != null) {
449                        asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
450                        asourcetoken.tokentype = ETokenType.ttsemicolon3;
451                    } else {
452                        lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try, -1);
453                        if (lctoken2 == null) {
454                            lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch, -1);
455                        }
456                        if (lctoken2 != null) {
457                            lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin, -2);
458                            if (lctoken3 != null) {
459                                asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
460                                asourcetoken.tokentype = ETokenType.ttsemicolon3;
461                            }
462                        }
463                    }
464                }
465
466                lctoken = getprevtoken(asourcetoken);
467                if ((lctoken != null)) {
468                    if (lctoken.tokentype == ETokenType.ttsemicolon) {
469                        // treat this semicolon as a whitespace
470                        asourcetoken.tokencode = TBaseType.lexspace;
471                    }
472                }
473            } else if (asourcetoken.tokentype == ETokenType.ttperiod) {
474                lctoken = getprevtoken(asourcetoken);
475                if (TBaseType.assigned(lctoken)) {
476                    // go.fieldname, go is a table alias, not a go statement
477                    if (lctoken.tokencode == TBaseType.rrw_go) {
478                        lctoken.tokencode = TBaseType.ident;
479                        lctoken.tokentype = ETokenType.ttidentifier;
480                    }
481                }
482            } else if (asourcetoken.tokencode == TBaseType.rrw_table) {
483                lctoken = getprevtoken(asourcetoken);
484                if (TBaseType.assigned(lctoken)) {
485                    if (lctoken.tokencode == TBaseType.rrw_lock) {
486                        lctoken.tokencode = TBaseType.rw_locktable;
487                    }
488                }
489            } else if (asourcetoken.tokencode == TBaseType.rrw_into) {
490                lctoken = getprevtoken(asourcetoken);
491                if (TBaseType.assigned(lctoken)) {
492                    if (lctoken.tokencode == TBaseType.rrw_sqlserver_copy) {
493                        lctoken.tokencode = TBaseType.rrw_sqlserver_copyinto;
494                    }
495                }
496            } else if (asourcetoken.tokencode == TBaseType.rrw_sqlserver_column) {
497                lctoken = getprevtoken(asourcetoken);
498                if (TBaseType.assigned(lctoken)) {
499                    if (lctoken.tokencode == TBaseType.rrw_drop) {
500                        asourcetoken.tokencode = TBaseType.rrw_sqlserver_drop_column;
501                    }
502                }
503            } else if (asourcetoken.tokencode == TBaseType.rrw_go) {
504                iskeywordgo = true;
505                lctoken = getprevtoken(asourcetoken);
506                if (TBaseType.assigned(lctoken)) {
507                    // go should not at same line as other sql statement
508                    if ((lctoken.lineNo == asourcetoken.lineNo) && (lctoken.tokencode != ';')) {
509                        iskeywordgo = false;
510                    }
511                }
512
513                if (iskeywordgo) {
514                    lcinopenrowset = false;
515                    lcnested = 0;
516                    lcprevtoken = asourcetoken;
517                } else {
518                    asourcetoken.tokencode = TBaseType.ident;
519                    asourcetoken.tokentype = ETokenType.ttidentifier;
520                }
521            } else if (asourcetoken.tokencode == TBaseType.rrw_primary) {
522                // primary key [clustered | nonclustered ] [hash] ( column list)
523                lcsteps = 2;
524                lcprevtoken = asourcetoken;
525            } else if (asourcetoken.tokencode == TBaseType.rrw_foreign) {
526                // foreign key [clustered | nonclustered ] ( column list)
527                lcsteps = 2;
528                lcprevtoken = asourcetoken;
529            } else if (asourcetoken.tokencode == TBaseType.rrw_unique) {
530                // unique [clustered | nonclustered ] [hash] ( column list)
531                lcsteps = 1;
532                lcprevtoken = asourcetoken;
533            } else if (asourcetoken.issolidtoken()) {
534                if (lcsteps > 0) {
535                    if (!(TBaseType.mysametext("clustered", asourcetoken.toString())
536                            || TBaseType.mysametext("nonclustered", asourcetoken.toString())
537                            || TBaseType.mysametext("hash", asourcetoken.toString())
538                    ))
539                        lcsteps--;
540                }
541            }
542
543            sourcetokenlist.add(asourcetoken);
544
545            asourcetoken = getanewsourcetoken();
546            if (asourcetoken == null) break;
547            yychar = asourcetoken.tokencode;
548        }
549    }
550
551    /**
552     * Get previous token in token list.
553     */
554    private TSourceToken getprevtoken(TSourceToken currentToken) {
555        if (currentToken == null || currentToken.posinlist == 0) {
556            return null;
557        }
558
559        for (int i = currentToken.posinlist - 1; i >= 0; i--) {
560            TSourceToken token = this.sourcetokenlist.get(i);
561            if (token.issolidtoken()) {
562                return token;
563            }
564        }
565        return null;
566    }
567
568    /**
569     * Check and adjust constraint token codes.
570     * <p>
571     * When PRIMARY KEY, FOREIGN KEY, or UNIQUE is followed by '(', we need to
572     * look back to see if there's a CONSTRAINT keyword. If found, change its
573     * token code from rrw_constraint (515) to rw_constraint2 (298).
574     *
575     * @param token The token after which to search (PRIMARY/FOREIGN/UNIQUE)
576     */
577    private void checkconstarinttoken(TSourceToken token) {
578        TSourceTokenList lcStList = token.container;
579        if (TBaseType.assigned(lcStList)) {
580            // Look back 2 solid tokens to find CONSTRAINT keyword
581            TSourceToken lcPPToken = lcStList.nextsolidtoken(token.posinlist, -2, false);
582            if (TBaseType.assigned(lcPPToken)) {
583                if (lcPPToken.tokencode == flexer.getkeywordvalue("constraint")) {
584                    // Change CONSTRAINT to special constraint2 token code
585                    lcPPToken.tokencode = TBaseType.rw_constraint2;
586                }
587            }
588        }
589    }
590
591    // ========== ODBC-Specific Raw Statement Extraction ==========
592
593    /**
594     * ODBC-specific raw statement extraction logic.
595     * <p>
596     * Extracted from: TGSqlParser.doodbcgetrawsqlstatements() (lines 12848-12850)
597     * <p>
598     * ODBC uses the same statement extraction logic as MSSQL.
599     */
600    private void doodbcgetrawsqlstatements(SqlParseResult.Builder builder) {
601        domssqlgetrawsqlstatements(builder);
602    }
603
604    /**
605     * MSSQL-specific raw statement extraction logic (inherited behavior).
606     * <p>
607     * This is the same extraction logic used by MSSQL, handling:
608     * <ul>
609     *   <li>Semicolon statement terminators</li>
610     *   <li>GO batch separators</li>
611     *   <li>BEGIN/END blocks</li>
612     *   <li>TRY/CATCH blocks</li>
613     *   <li>Stored procedures, functions, and triggers</li>
614     * </ul>
615     */
616    private void domssqlgetrawsqlstatements(SqlParseResult.Builder builder) {
617        int errorcount = 0;
618        int case_end_nest = 0;
619
620        if (TBaseType.assigned(sqlstatements)) sqlstatements.clear();
621        if (!TBaseType.assigned(sourcetokenlist)) {
622            builder.errorCode(-1);
623            builder.errorMessage("Source token list is null");
624            return;
625        }
626
627        gcurrentsqlstatement = null;
628        EFindSqlStateType gst = EFindSqlStateType.stnormal;
629        int lcblocklevel = 0;
630        int lctrycatchlevel = 0;
631        TSourceToken lcprevsolidtoken = null, lcnextsolidtoken, lcnnextsolidtoken;
632        TSourceToken ast = null;
633        int i, lcMergeInSelectNested = 0;
634        boolean lcisendconversation, lcstillinsql, lcMergeInSelect = false;
635
636        for (i = 0; i < sourcetokenlist.size(); i++) {
637
638            if ((ast != null) && (ast.issolidtoken()))
639                lcprevsolidtoken = ast;
640
641            ast = sourcetokenlist.get(i);
642            sourcetokenlist.curpos = i;
643
644            if (ast.tokencode == TBaseType.rrw_for) {
645                TSourceToken st1 = ast.nextSolidToken();
646                if ((st1 != null) && (st1.tokencode == TBaseType.rrw_system_time)) {
647                    ast.tokencode = TBaseType.rw_for_system_time;
648                }
649            }
650
651            if (lcMergeInSelect) {
652                if (ast.tokencode == '(') lcMergeInSelectNested++;
653                if (ast.tokencode == ')') {
654                    lcMergeInSelectNested--;
655                    if (lcMergeInSelectNested == 0) {
656                        lcMergeInSelect = false;
657                    }
658                }
659                gcurrentsqlstatement.sourcetokenlist.add(ast);
660                continue;
661            }
662
663            if (ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement) {
664                gcurrentsqlstatement.sourcetokenlist.add(ast);
665                continue;
666            }
667
668            if (ast.tokencode == TBaseType.rrw_minus) {
669                TSourceToken st1 = ast.searchToken('(', 1);
670                if (st1 == null) {
671                    st1 = ast.searchToken(TBaseType.rrw_select, 1);
672                    if (st1 == null) {
673                        ast.tokencode = TBaseType.ident;
674                    }
675                }
676            } else if (ast.tokencode == TBaseType.rrw_merge) {
677                TSourceToken st1 = ast.nextSolidToken();
678                if (st1.tokencode == TBaseType.rrw_join) {
679                    ast.tokencode = TBaseType.rrw_merge2_sqlserver;
680                }
681                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '(')) {
682                    lcMergeInSelect = true;
683                    lcMergeInSelectNested++;
684                    gcurrentsqlstatement.sourcetokenlist.add(ast);
685                    continue;
686                }
687            } else if (ast.tokencode == TBaseType.rrw_sqlserver_value) {
688                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
689                    TSourceToken st1 = ast.searchToken('(', 1);
690                    if (st1 != null) {
691                        ast.tokencode = TBaseType.rrw_xml_value;
692                    }
693                }
694            } else if (ast.tokencode == TBaseType.rrw_sqlserver_modify) {
695                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
696                    TSourceToken st1 = ast.searchToken('(', 1);
697                    if (st1 != null) {
698                        ast.tokencode = TBaseType.rrw_xml_modify;
699                    }
700                }
701            } else if (ast.tokencode == TBaseType.rrw_sqlserver_query) {
702                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
703                    TSourceToken st1 = ast.searchToken('(', 1);
704                    if (st1 != null) {
705                        ast.tokencode = TBaseType.rrw_xml_query;
706                    }
707                }
708            } else if (ast.tokencode == TBaseType.rrw_sqlserver_exist) {
709                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
710                    TSourceToken st1 = ast.searchToken('(', 1);
711                    if (st1 != null) {
712                        ast.tokencode = TBaseType.rrw_xml_exist;
713                    }
714                }
715            } else if (ast.tokencode == TBaseType.rrw_sqlserver_nodes) {
716                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
717                    TSourceToken st1 = ast.searchToken('(', 1);
718                    if (st1 != null) {
719                        ast.tokencode = TBaseType.rrw_xml_nodes;
720                    }
721                }
722            } else if (ast.tokencode == TBaseType.rrw_check) {
723                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == TBaseType.rrw_with)) {
724                    lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with;
725                }
726            } else if (ast.tokencode == TBaseType.rrw_sqlserver_next) {
727                TSourceToken st1 = ast.nextSolidToken();
728                if ((st1 != null) && (st1.tokencode == '.')) {
729                    ast.tokencode = TBaseType.ident;
730                }
731            } else if (ast.tokencode == TBaseType.rrw_fetch) {
732                if ((lcprevsolidtoken != null) && ((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row) || (lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))) {
733                    TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open, -1);
734                    if (prev2 == null) {
735                        ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch;
736                    }
737                }
738            } else if ((ast.tokencode == TBaseType.rrw_exec) || (ast.tokencode == TBaseType.rrw_execute)) {
739                // search ;2 after execute
740                // EXECUTE ApxSQL_Test_Triggers_Add;2  @TableName, @AddFlag
741                int searchRange = 4;
742                TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine();
743                if (endTokenInSameLine != null) {
744                    searchRange = endTokenInSameLine.posinlist - ast.posinlist;
745                }
746                TSourceToken st1 = ast.searchToken(';', searchRange);
747                if (st1 != null) {
748                    TSourceToken numSt = st1.nextSolidToken();
749                    if ((numSt != null) && (numSt.tokentype == ETokenType.ttnumber)) {
750                        st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number;
751                        st1.tokentype = ETokenType.ttidentifier;
752                    }
753                }
754            } else if (ast.tokencode == TBaseType.rrw_sqlserver_trim) {
755                TSourceToken st1 = ast.nextSolidToken();
756                if (st1 != null) {
757                    if (st1.tokencode == '(') {
758                        // keep as trim keyword
759                    } else {
760                        ast.tokencode = TBaseType.ident;
761                    }
762                }
763            }
764
765            if (gst == EFindSqlStateType.ststoredprocedurebody) {
766                if (!((ast.tokencode == TBaseType.rrw_go)
767                        || (ast.tokencode == TBaseType.rrw_create)
768                        || (ast.tokencode == TBaseType.rrw_alter))) {
769                    gcurrentsqlstatement.sourcetokenlist.add(ast);
770                    continue;
771                }
772            }
773
774            TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement);
775
776            switch (gst) {
777                case sterror: {
778                    if (TBaseType.assigned(lcnextsqlstatement)) {
779                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
780                        gcurrentsqlstatement = lcnextsqlstatement;
781                        gcurrentsqlstatement.sourcetokenlist.add(ast);
782                        gst = EFindSqlStateType.stsql;
783                    } else if ((ast.tokentype == ETokenType.ttsemicolon)) {
784                        gcurrentsqlstatement.sourcetokenlist.add(ast);
785                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
786                        gst = EFindSqlStateType.stnormal;
787                    } else {
788                        gcurrentsqlstatement.sourcetokenlist.add(ast);
789                    }
790                    break;
791                }
792                case stnormal: {
793                    if ((ast.tokencode == TBaseType.cmtdoublehyphen)
794                            || (ast.tokencode == TBaseType.cmtslashstar)
795                            || (ast.tokencode == TBaseType.lexspace)
796                            || (ast.tokencode == TBaseType.lexnewline)
797                            || (ast.tokentype == ETokenType.ttsemicolon)) {
798                        if (TBaseType.assigned(gcurrentsqlstatement)) {
799                            gcurrentsqlstatement.sourcetokenlist.add(ast);
800                        }
801
802                        if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) {
803                            if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) {
804                                // ;;;; continuous semicolon,treat it as comment
805                                ast.tokentype = ETokenType.ttsimplecomment;
806                                ast.tokencode = TBaseType.cmtdoublehyphen;
807                            }
808                        }
809
810                        continue;
811                    }
812
813                    gcurrentsqlstatement = lcnextsqlstatement;
814
815                    if (TBaseType.assigned(gcurrentsqlstatement)) {
816                        switch (gcurrentsqlstatement.sqlstatementtype) {
817                            case sstmssqlcreateprocedure:
818                            case sstmssqlcreatefunction:
819                            case sstcreatetrigger:
820                            case sstmssqlalterprocedure:
821                            case sstmssqlalterfunction:
822                            case sstmssqlaltertrigger: {
823                                gcurrentsqlstatement.sourcetokenlist.add(ast);
824                                gst = EFindSqlStateType.ststoredprocedure;
825                                break;
826                            }
827                            case sstmssqlbegintry:
828                            case sstmssqlbegincatch: {
829                                gcurrentsqlstatement.sourcetokenlist.add(ast);
830                                gst = EFindSqlStateType.sttrycatch;
831                                lctrycatchlevel = 0;
832                                break;
833                            }
834                            case sstmssqlgo: {
835                                gcurrentsqlstatement.sourcetokenlist.add(ast);
836                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
837                                gst = EFindSqlStateType.stnormal;
838                                break;
839                            }
840                            default: {
841                                gcurrentsqlstatement.sourcetokenlist.add(ast);
842                                gst = EFindSqlStateType.stsql;
843                                break;
844                            }
845                        }
846                    } else {
847                        if (ast.tokencode == TBaseType.rrw_begin) {
848                            gcurrentsqlstatement = new TMssqlBlock(vendor);
849                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
850                            gcurrentsqlstatement.sourcetokenlist.add(ast);
851                            gst = EFindSqlStateType.stblock;
852                        } else {
853                            if (sqlstatements.size() == 0) {
854                                //first statement of mssql batch, treat it as exec sp
855                                gst = EFindSqlStateType.stsql;
856                                gcurrentsqlstatement = new TMssqlExecute(vendor);
857                                gcurrentsqlstatement.sourcetokenlist.add(ast);
858                            } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) {
859                                // prev sql is go, treat it as exec sp
860                                gst = EFindSqlStateType.stsql;
861                                gcurrentsqlstatement = new TMssqlExecute(vendor);
862                                gcurrentsqlstatement.sourcetokenlist.add(ast);
863                            }
864                        }
865                    }
866
867                    if (!TBaseType.assigned(gcurrentsqlstatement)) //error tokentext found
868                    {
869                        this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo)
870                                , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist));
871
872                        ast.tokentype = ETokenType.tttokenlizererrortoken;
873                        gst = EFindSqlStateType.sterror;
874
875                        gcurrentsqlstatement = new TUnknownSqlStatement(vendor);
876                        gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
877                        gcurrentsqlstatement.sourcetokenlist.add(ast);
878                    }
879                    break;
880                }
881                case stblock: {
882                    if (TBaseType.assigned(lcnextsqlstatement)) {
883                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
884                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
885                            gcurrentsqlstatement = lcnextsqlstatement;
886                            gcurrentsqlstatement.sourcetokenlist.add(ast);
887                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
888                            gst = EFindSqlStateType.stnormal;
889                        } else {
890                            lcnextsqlstatement = null;
891                        }
892                    }
893
894                    if (gst == EFindSqlStateType.stblock) {
895                        gcurrentsqlstatement.sourcetokenlist.add(ast);
896                        if (ast.tokencode == TBaseType.rrw_begin) {
897                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
898                            if (TBaseType.assigned(lcnextsolidtoken)) {
899                                if (!((lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_tran)
900                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_transaction)
901                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_distributed)
902                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_dialog)
903                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation)
904                                ))
905                                    lcblocklevel++;
906                            } else
907                                lcblocklevel++;
908
909                        } else if (ast.tokencode == TBaseType.rrw_case)
910                            lcblocklevel++;
911                        else if (ast.tokencode == TBaseType.rrw_end) {
912
913                            lcisendconversation = false;
914
915                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
916                            if (TBaseType.assigned(lcnextsolidtoken)) {
917                                if (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation)
918                                    lcisendconversation = true;
919                            }
920
921                            if (!lcisendconversation) {
922
923                                if (lcblocklevel == 0) {
924                                    if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
925                                        if (TBaseType.assigned(lcnextsolidtoken)) {
926                                            if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
927                                                gst = EFindSqlStateType.stsql;
928                                            } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) {
929                                                lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false);
930                                                if (TBaseType.assigned(lcnnextsolidtoken)) {
931                                                    if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) {
932                                                        gst = EFindSqlStateType.stsql;
933                                                    }
934                                                }
935                                            }
936                                        }
937                                    }
938
939                                    if (gst != EFindSqlStateType.stsql) {
940                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
941                                        gst = EFindSqlStateType.stnormal;
942                                    }
943
944                                } else {
945                                    lcblocklevel--;
946                                }
947
948                            }
949                        }
950                    }
951                    break;
952                }
953                case sttrycatch: {
954
955                    if (TBaseType.assigned(lcnextsqlstatement)) {
956                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
957                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
958                            gcurrentsqlstatement = lcnextsqlstatement;
959                            gcurrentsqlstatement.sourcetokenlist.add(ast);
960                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
961                            gst = EFindSqlStateType.stnormal;
962                        } else {
963                            if (
964                                    (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)
965                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
966                            )
967                                lctrycatchlevel++;
968                            lcnextsqlstatement = null;
969                        }
970                    }
971
972                    if (gst == EFindSqlStateType.sttrycatch) {
973                        gcurrentsqlstatement.sourcetokenlist.add(ast);
974                        if ((ast.tokencode == TBaseType.rrw_try) ||
975                                (ast.tokencode == TBaseType.rrw_catch)) {
976                            if (TBaseType.assigned(lcprevsolidtoken)) {
977                                if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) {
978                                    if (lctrycatchlevel == 0) {
979                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
980                                        gst = EFindSqlStateType.stnormal;
981                                    } else
982                                        lctrycatchlevel--;
983                                }
984                            }
985                        }
986                    }
987                    break;
988                }
989                case stprocedureWithReturn: {
990                    // found return statement in create procedure/function
991
992                    if (TBaseType.assigned(lcnextsqlstatement)) {
993                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
994                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
995                            gcurrentsqlstatement = lcnextsqlstatement;
996                            gcurrentsqlstatement.sourcetokenlist.add(ast);
997                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
998                            gst = EFindSqlStateType.stnormal;
999                            break;
1000                        }
1001                    }
1002
1003                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1004                    if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)) {
1005                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1006                        gst = EFindSqlStateType.stnormal;
1007                    }
1008                    break;
1009                }
1010                case stsql: {
1011                    if ((ast.tokentype == ETokenType.ttsemicolon)) {
1012                        lcstillinsql = false;
1013                        if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
1014                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
1015                            if (TBaseType.assigned(lcnextsolidtoken)) {
1016                                if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
1017                                    // if ( expr stmt; else
1018                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1019                                    lcstillinsql = true;
1020                                }
1021
1022                            }
1023                        }
1024
1025                        if (!lcstillinsql) {
1026                            gst = EFindSqlStateType.stnormal;
1027                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1028                            gcurrentsqlstatement.semicolonended = ast;
1029                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1030                        }
1031
1032                    } else if (TBaseType.assigned(lcnextsqlstatement)) {
1033
1034                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
1035                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1036                            gcurrentsqlstatement = lcnextsqlstatement;
1037                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1038                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1039                            gst = EFindSqlStateType.stnormal;
1040                            continue;
1041                        }
1042
1043                        switch (gcurrentsqlstatement.sqlstatementtype) {
1044                            case sstmssqlif:
1045                            case sstmssqlwhile: {
1046                                if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
1047                                        || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) {
1048                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1049                                    gst = EFindSqlStateType.stblock;
1050                                    lcblocklevel = 1;
1051                                    lcnextsqlstatement = null;
1052                                    continue;
1053
1054                                } else if (gcurrentsqlstatement.dummytag == 1) {
1055                                    // if ( cond ^stmt nextstmt (^ stands for current pos)
1056                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1057
1058                                    if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1059                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile))
1060                                        gcurrentsqlstatement.dummytag = 1;
1061                                    else
1062                                        gcurrentsqlstatement.dummytag = 0;
1063
1064                                    lcnextsqlstatement = null;
1065                                    continue;
1066                                } else {
1067                                    if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
1068                                        if ((ast.nextSolidToken() != null) && (ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)) {
1069                                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1070                                            lcnextsqlstatement = null;
1071                                            continue;
1072                                        }
1073                                    }
1074                                }
1075                                break;
1076                            }
1077                            case sstmssqlalterqueue: {
1078                                if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) {
1079                                    // execute can't be used to delimite alter queue
1080                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1081                                    lcnextsqlstatement = null;
1082                                    continue;
1083
1084                                }
1085                                break;
1086                            }
1087                            case sstmssqlcreateschema: {
1088                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1089                                lcnextsqlstatement = null;
1090                                continue;
1091                            }
1092                        }
1093
1094                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1095                        gcurrentsqlstatement = lcnextsqlstatement;
1096                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1097
1098                        switch (gcurrentsqlstatement.sqlstatementtype) {
1099                            case sstmssqlcreateprocedure:
1100                            case sstmssqlcreatefunction:
1101                            case sstcreatetrigger:
1102                            case sstmssqlalterprocedure:
1103                            case sstmssqlalterfunction:
1104                            case sstmssqlaltertrigger: {
1105                                gst = EFindSqlStateType.ststoredprocedure;
1106                                break;
1107                            }
1108                            case sstmssqlbegintry:
1109                            case sstmssqlbegincatch: {
1110                                gst = EFindSqlStateType.sttrycatch;
1111                                lctrycatchlevel = 0;
1112                                break;
1113                            }
1114                            case sstmssqlgo: {
1115                                gst = EFindSqlStateType.stnormal;
1116                                break;
1117                            }
1118                            default: {
1119                                gst = EFindSqlStateType.stsql;
1120                                break;
1121                            }
1122                        }
1123
1124                    } else if ((ast.tokencode == TBaseType.rrw_begin)) {
1125                        if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1126                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) {
1127                            gst = EFindSqlStateType.stblock;
1128                            lcblocklevel = 0;
1129                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1130                        } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) {
1131                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1132                            gcurrentsqlstatement = new TMssqlBlock(vendor);
1133                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
1134                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1135                            gst = EFindSqlStateType.stblock;
1136                        } else {
1137                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1138                        }
1139                    } else if ((ast.tokencode == TBaseType.rrw_case)) {
1140                        case_end_nest++;
1141                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1142                    } else if ((ast.tokencode == TBaseType.rrw_end)) {
1143                        if (case_end_nest > 0) {
1144                            case_end_nest--;
1145                        }
1146                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1147                    } else if ((ast.tokencode == TBaseType.rrw_else)) {
1148                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1149                        if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1150                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
1151                        ) && (case_end_nest == 0))
1152                            gcurrentsqlstatement.dummytag = 1;
1153                    } else {
1154                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1155                    }
1156                    break;
1157                }
1158                case ststoredprocedure: {
1159                    if (TBaseType.assigned(lcnextsqlstatement)) {
1160                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
1161                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1162                            gcurrentsqlstatement = lcnextsqlstatement;
1163                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1164                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1165                            gst = EFindSqlStateType.stnormal;
1166                        } else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn) {
1167                            gst = EFindSqlStateType.stprocedureWithReturn;
1168                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1169                            lcnextsqlstatement = null;
1170                        } else {
1171                            gst = EFindSqlStateType.ststoredprocedurebody;
1172                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1173
1174                            lcnextsqlstatement = null;
1175                        }
1176                    }
1177
1178                    if (gst == EFindSqlStateType.ststoredprocedure) {
1179                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1180                        if (ast.tokencode == TBaseType.rrw_begin) {
1181                            gst = EFindSqlStateType.stblock;
1182                        }
1183                    }
1184                    break;
1185                }
1186                case ststoredprocedurebody: {
1187                    if (TBaseType.assigned(lcnextsqlstatement)) {
1188                        switch (lcnextsqlstatement.sqlstatementtype) {
1189                            case sstmssqlgo: {
1190                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1191                                gcurrentsqlstatement = lcnextsqlstatement;
1192                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1193                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1194                                gst = EFindSqlStateType.stnormal;
1195                                break;
1196                            }
1197                            case sstmssqlcreateprocedure:
1198                            case sstmssqlcreatefunction:
1199                            case sstcreatetrigger:
1200                            case sstmssqlalterprocedure:
1201                            case sstmssqlalterfunction:
1202                            case sstmssqlaltertrigger: {
1203                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1204                                gcurrentsqlstatement = lcnextsqlstatement;
1205                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1206                                gst = EFindSqlStateType.ststoredprocedure;
1207                                break;
1208                            }
1209                            case sstcreateview:
1210                            case sstcreatetable: {
1211
1212                                boolean readForNewStmt = false;
1213                                TSourceToken st1 = ast.searchToken(';', -1);
1214                                if (st1 != null) {
1215                                    TSourceToken st2 = ast.searchToken(TBaseType.rrw_end, -2);
1216                                    if (st2 != null) {
1217                                        readForNewStmt = true;
1218                                    }
1219                                }
1220
1221                                if (readForNewStmt) {
1222                                    onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1223                                    gcurrentsqlstatement = lcnextsqlstatement;
1224                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1225                                    gst = EFindSqlStateType.stsql;
1226                                } else {
1227                                    lcnextsqlstatement = null;
1228                                }
1229                                break;
1230                            }
1231                            case sstmssqlDropSecurityPolicy:
1232                            case sstmssqlAlterSecurityPolicy:
1233                            case sstmssqlCreateSecurityPolicy:
1234                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1235                                gcurrentsqlstatement = lcnextsqlstatement;
1236                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1237                                gst = EFindSqlStateType.stsql;
1238
1239                                break;
1240                            default: {
1241                                lcnextsqlstatement = null;
1242                                break;
1243                            }
1244                        }
1245                    }
1246
1247                    if (gst == EFindSqlStateType.ststoredprocedurebody)
1248                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1249                }
1250                break;
1251            }
1252        }
1253
1254        //last statement
1255        if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) {
1256            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder);
1257        }
1258
1259        // Set results in builder
1260        builder.sqlStatements(this.sqlstatements);
1261        builder.errorCode(errorcount);
1262        builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount));
1263    }
1264}