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