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                } else if ((st1 != null) && TBaseType.mycomparetext(st1.getAstext(), "PATH") == 0) {
636                    ast.tokencode = TBaseType.rw_for_path;
637                }
638            }
639
640            if (lcMergeInSelect) {
641                if (ast.tokencode == '(') lcMergeInSelectNested++;
642                if (ast.tokencode == ')') {
643                    lcMergeInSelectNested--;
644                    if (lcMergeInSelectNested == 0) {
645                        lcMergeInSelect = false;
646                    }
647                }
648                gcurrentsqlstatement.sourcetokenlist.add(ast);
649                continue;
650            }
651
652            if (ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement) {
653                gcurrentsqlstatement.sourcetokenlist.add(ast);
654                continue;
655            }
656
657            if (ast.tokencode == TBaseType.rrw_minus) {
658                TSourceToken st1 = ast.searchToken('(', 1);
659                if (st1 == null) {
660                    st1 = ast.searchToken(TBaseType.rrw_select, 1);
661                    if (st1 == null) {
662                        ast.tokencode = TBaseType.ident;
663                    }
664                }
665            } else if (ast.tokencode == TBaseType.rrw_merge) {
666                TSourceToken st1 = ast.nextSolidToken();
667                if (st1.tokencode == TBaseType.rrw_join) {
668                    ast.tokencode = TBaseType.rrw_merge2_sqlserver;
669                }
670                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '(')) {
671                    lcMergeInSelect = true;
672                    lcMergeInSelectNested++;
673                    gcurrentsqlstatement.sourcetokenlist.add(ast);
674                    continue;
675                }
676            } else if (ast.tokencode == TBaseType.rrw_sqlserver_value) {
677                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
678                    TSourceToken st1 = ast.searchToken('(', 1);
679                    if (st1 != null) {
680                        ast.tokencode = TBaseType.rrw_xml_value;
681                    }
682                }
683            } else if (ast.tokencode == TBaseType.rrw_sqlserver_modify) {
684                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
685                    TSourceToken st1 = ast.searchToken('(', 1);
686                    if (st1 != null) {
687                        ast.tokencode = TBaseType.rrw_xml_modify;
688                    }
689                }
690            } else if (ast.tokencode == TBaseType.rrw_sqlserver_query) {
691                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
692                    TSourceToken st1 = ast.searchToken('(', 1);
693                    if (st1 != null) {
694                        ast.tokencode = TBaseType.rrw_xml_query;
695                    }
696                }
697            } else if (ast.tokencode == TBaseType.rrw_sqlserver_exist) {
698                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
699                    TSourceToken st1 = ast.searchToken('(', 1);
700                    if (st1 != null) {
701                        ast.tokencode = TBaseType.rrw_xml_exist;
702                    }
703                }
704            } else if (ast.tokencode == TBaseType.rrw_sqlserver_nodes) {
705                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) {
706                    TSourceToken st1 = ast.searchToken('(', 1);
707                    if (st1 != null) {
708                        ast.tokencode = TBaseType.rrw_xml_nodes;
709                    }
710                }
711            } else if (ast.tokencode == TBaseType.rrw_check) {
712                if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == TBaseType.rrw_with)) {
713                    lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with;
714                }
715            } else if (ast.tokencode == TBaseType.rrw_sqlserver_next) {
716                TSourceToken st1 = ast.nextSolidToken();
717                if ((st1 != null) && (st1.tokencode == '.')) {
718                    ast.tokencode = TBaseType.ident;
719                }
720            } else if (ast.tokencode == TBaseType.rrw_fetch) {
721                if ((lcprevsolidtoken != null) && ((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row) || (lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))) {
722                    TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open, -1);
723                    if (prev2 == null) {
724                        ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch;
725                    }
726                }
727            } else if ((ast.tokencode == TBaseType.rrw_exec) || (ast.tokencode == TBaseType.rrw_execute)) {
728                // search ;2 after execute
729                // EXECUTE ApxSQL_Test_Triggers_Add;2  @TableName, @AddFlag
730                int searchRange = 4;
731                TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine();
732                if (endTokenInSameLine != null) {
733                    searchRange = endTokenInSameLine.posinlist - ast.posinlist;
734                }
735                TSourceToken st1 = ast.searchToken(';', searchRange);
736                if (st1 != null) {
737                    TSourceToken numSt = st1.nextSolidToken();
738                    if ((numSt != null) && (numSt.tokentype == ETokenType.ttnumber)) {
739                        st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number;
740                        st1.tokentype = ETokenType.ttidentifier;
741                    }
742                }
743            } else if (ast.tokencode == TBaseType.rrw_sqlserver_trim) {
744                TSourceToken st1 = ast.nextSolidToken();
745                if (st1 != null) {
746                    if (st1.tokencode == '(') {
747                        // keep as trim keyword
748                    } else {
749                        ast.tokencode = TBaseType.ident;
750                    }
751                }
752            }
753
754            if (vendor == EDbVendor.dbvopenedge){
755                if (ast.tokencode == TBaseType.rrw_order){
756                        TSourceToken st1 = ast.searchToken(TBaseType.rrw_by,1);
757                        if (st1 == null) {
758                            ast.tokencode = TBaseType.ident;
759                        }
760                }else if (ast.tokencode == TBaseType.rrw_with){
761                        TSourceToken st1 = ast.searchToken(TBaseType.rrw_check,1);
762                        if (st1 != null) {
763                            ast.tokencode = TBaseType.rrw_openedge_with_check;
764                        }
765                }
766            }
767
768            if (gst == EFindSqlStateType.ststoredprocedurebody) {
769                if (!((ast.tokencode == TBaseType.rrw_go)
770                        || (ast.tokencode == TBaseType.rrw_create)
771                        || (ast.tokencode == TBaseType.rrw_alter))) {
772                    gcurrentsqlstatement.sourcetokenlist.add(ast);
773                    continue;
774                }
775            }
776
777            TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement);
778
779            switch (gst) {
780                case sterror: {
781                    if (TBaseType.assigned(lcnextsqlstatement)) {
782                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
783                        gcurrentsqlstatement = lcnextsqlstatement;
784                        gcurrentsqlstatement.sourcetokenlist.add(ast);
785                        gst = EFindSqlStateType.stsql;
786                    } else if ((ast.tokentype == ETokenType.ttsemicolon)) {
787                        gcurrentsqlstatement.sourcetokenlist.add(ast);
788                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
789                        gst = EFindSqlStateType.stnormal;
790                    } else {
791                        gcurrentsqlstatement.sourcetokenlist.add(ast);
792                    }
793                    break;
794                }
795                case stnormal: {
796                    if ((ast.tokencode == TBaseType.cmtdoublehyphen)
797                            || (ast.tokencode == TBaseType.cmtslashstar)
798                            || (ast.tokencode == TBaseType.lexspace)
799                            || (ast.tokencode == TBaseType.lexnewline)
800                            || (ast.tokentype == ETokenType.ttsemicolon)) {
801                        if (TBaseType.assigned(gcurrentsqlstatement)) {
802                            gcurrentsqlstatement.sourcetokenlist.add(ast);
803                        }
804
805                        if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) {
806                            if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) {
807                                // ;;;; continuous semicolon,treat it as comment
808                                ast.tokentype = ETokenType.ttsimplecomment;
809                                ast.tokencode = TBaseType.cmtdoublehyphen;
810                            }
811                        }
812
813                        continue;
814                    }
815
816                    gcurrentsqlstatement = lcnextsqlstatement;
817
818                    if (TBaseType.assigned(gcurrentsqlstatement)) {
819                        switch (gcurrentsqlstatement.sqlstatementtype) {
820                            case sstmssqlcreateprocedure:
821                            case sstmssqlcreatefunction:
822                            case sstcreatetrigger:
823                            case sstmssqlalterprocedure:
824                            case sstmssqlalterfunction:
825                            case sstmssqlaltertrigger: {
826                                gcurrentsqlstatement.sourcetokenlist.add(ast);
827                                gst = EFindSqlStateType.ststoredprocedure;
828                                break;
829                            }
830                            case sstmssqlbegintry:
831                            case sstmssqlbegincatch: {
832                                gcurrentsqlstatement.sourcetokenlist.add(ast);
833                                gst = EFindSqlStateType.sttrycatch;
834                                lctrycatchlevel = 0;
835                                break;
836                            }
837                            case sstmssqlgo: {
838                                gcurrentsqlstatement.sourcetokenlist.add(ast);
839                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
840                                gst = EFindSqlStateType.stnormal;
841                                break;
842                            }
843                            default: {
844                                gcurrentsqlstatement.sourcetokenlist.add(ast);
845                                gst = EFindSqlStateType.stsql;
846                                break;
847                            }
848                        }
849                    } else {
850                        if (ast.tokencode == TBaseType.rrw_begin) {
851                            gcurrentsqlstatement = new TMssqlBlock(vendor);
852                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
853                            gcurrentsqlstatement.sourcetokenlist.add(ast);
854                            gst = EFindSqlStateType.stblock;
855                        } else {
856                            if (sqlstatements.size() == 0) {
857                                //first statement of mssql batch, treat it as exec sp
858                                gst = EFindSqlStateType.stsql;
859                                gcurrentsqlstatement = new TMssqlExecute(vendor);
860                                gcurrentsqlstatement.sourcetokenlist.add(ast);
861                            } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) {
862                                // prev sql is go, treat it as exec sp
863                                gst = EFindSqlStateType.stsql;
864                                gcurrentsqlstatement = new TMssqlExecute(vendor);
865                                gcurrentsqlstatement.sourcetokenlist.add(ast);
866                            }
867                        }
868                    }
869
870                    if (!TBaseType.assigned(gcurrentsqlstatement)) //error tokentext found
871                    {
872                        this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo)
873                                , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist));
874
875                        ast.tokentype = ETokenType.tttokenlizererrortoken;
876                        gst = EFindSqlStateType.sterror;
877
878                        gcurrentsqlstatement = new TUnknownSqlStatement(vendor);
879                        gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
880                        gcurrentsqlstatement.sourcetokenlist.add(ast);
881                    }
882                    break;
883                }
884                case stblock: {
885                    if (TBaseType.assigned(lcnextsqlstatement)) {
886                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
887                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
888                            gcurrentsqlstatement = lcnextsqlstatement;
889                            gcurrentsqlstatement.sourcetokenlist.add(ast);
890                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
891                            gst = EFindSqlStateType.stnormal;
892                        } else {
893                            lcnextsqlstatement = null;
894                        }
895                    }
896
897                    if (gst == EFindSqlStateType.stblock) {
898                        gcurrentsqlstatement.sourcetokenlist.add(ast);
899                        if (ast.tokencode == TBaseType.rrw_begin) {
900                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
901                            if (TBaseType.assigned(lcnextsolidtoken)) {
902                                if (!((lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_tran)
903                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_transaction)
904                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_distributed)
905                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_dialog)
906                                        || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation)
907                                ))
908                                    lcblocklevel++;
909                            } else
910                                lcblocklevel++;
911
912                        } else if (ast.tokencode == TBaseType.rrw_case)
913                            lcblocklevel++;
914                        else if (ast.tokencode == TBaseType.rrw_end) {
915
916                            lcisendconversation = false;
917
918                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
919                            if (TBaseType.assigned(lcnextsolidtoken)) {
920                                if (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation)
921                                    lcisendconversation = true;
922                            }
923
924                            if (!lcisendconversation) {
925
926                                if (lcblocklevel == 0) {
927                                    if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
928                                        if (TBaseType.assigned(lcnextsolidtoken)) {
929                                            if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
930                                                gst = EFindSqlStateType.stsql;
931                                            } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) {
932                                                lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false);
933                                                if (TBaseType.assigned(lcnnextsolidtoken)) {
934                                                    if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) {
935                                                        gst = EFindSqlStateType.stsql;
936                                                    }
937                                                }
938                                            }
939                                        }
940                                    }
941
942                                    if (gst != EFindSqlStateType.stsql) {
943                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
944                                        gst = EFindSqlStateType.stnormal;
945                                    }
946
947                                } else {
948                                    lcblocklevel--;
949                                }
950
951                            }
952                        }
953                    }
954                    break;
955                }
956                case sttrycatch: {
957
958                    if (TBaseType.assigned(lcnextsqlstatement)) {
959                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
960                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
961                            gcurrentsqlstatement = lcnextsqlstatement;
962                            gcurrentsqlstatement.sourcetokenlist.add(ast);
963                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
964                            gst = EFindSqlStateType.stnormal;
965                        } else {
966                            if (
967                                    (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)
968                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
969                            )
970                                lctrycatchlevel++;
971                            lcnextsqlstatement = null;
972                        }
973                    }
974
975                    if (gst == EFindSqlStateType.sttrycatch) {
976                        gcurrentsqlstatement.sourcetokenlist.add(ast);
977                        if ((ast.tokencode == TBaseType.rrw_try) ||
978                                (ast.tokencode == TBaseType.rrw_catch)) {
979                            if (TBaseType.assigned(lcprevsolidtoken)) {
980                                if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) {
981                                    if (lctrycatchlevel == 0) {
982                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
983                                        gst = EFindSqlStateType.stnormal;
984                                    } else
985                                        lctrycatchlevel--;
986                                }
987                            }
988                        }
989                    }
990                    break;
991                }
992                case stprocedureWithReturn: {
993                    // found return statement in create procedure/function
994
995                    if (TBaseType.assigned(lcnextsqlstatement)) {
996                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
997                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
998                            gcurrentsqlstatement = lcnextsqlstatement;
999                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1000                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1001                            gst = EFindSqlStateType.stnormal;
1002                            break;
1003                        }
1004                    }
1005
1006                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1007                    if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)) {
1008                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1009                        gst = EFindSqlStateType.stnormal;
1010                    }
1011                    break;
1012                }
1013                case stsql: {
1014                    if ((ast.tokentype == ETokenType.ttsemicolon)) {
1015                        lcstillinsql = false;
1016                        if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
1017                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
1018                            if (TBaseType.assigned(lcnextsolidtoken)) {
1019                                if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
1020                                    // if ( expr stmt; else
1021                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1022                                    lcstillinsql = true;
1023                                }
1024
1025                            }
1026                        }
1027
1028                        if (!lcstillinsql) {
1029                            gst = EFindSqlStateType.stnormal;
1030                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1031                            gcurrentsqlstatement.semicolonended = ast;
1032                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1033                        }
1034
1035                    } else if (TBaseType.assigned(lcnextsqlstatement)) {
1036
1037                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
1038                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1039                            gcurrentsqlstatement = lcnextsqlstatement;
1040                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1041                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1042                            gst = EFindSqlStateType.stnormal;
1043                            continue;
1044                        }
1045
1046                        switch (gcurrentsqlstatement.sqlstatementtype) {
1047                            case sstmssqlif:
1048                            case sstmssqlwhile: {
1049                                if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
1050                                        || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) {
1051                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1052                                    gst = EFindSqlStateType.stblock;
1053                                    lcblocklevel = 1;
1054                                    lcnextsqlstatement = null;
1055                                    continue;
1056
1057                                } else if (gcurrentsqlstatement.dummytag == 1) {
1058                                    // if ( cond ^stmt nextstmt (^ stands for current pos)
1059                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1060
1061                                    if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1062                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile))
1063                                        gcurrentsqlstatement.dummytag = 1;
1064                                    else
1065                                        gcurrentsqlstatement.dummytag = 0;
1066
1067                                    lcnextsqlstatement = null;
1068                                    continue;
1069                                } else {
1070                                    if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
1071                                        if ((ast.nextSolidToken() != null) && (ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)) {
1072                                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1073                                            lcnextsqlstatement = null;
1074                                            continue;
1075                                        }
1076                                    }
1077                                }
1078                                break;
1079                            }
1080                            case sstmssqlalterqueue: {
1081                                if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) {
1082                                    // execute can't be used to delimite alter queue
1083                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1084                                    lcnextsqlstatement = null;
1085                                    continue;
1086
1087                                }
1088                                break;
1089                            }
1090                            case sstmssqlcreateschema: {
1091                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1092                                lcnextsqlstatement = null;
1093                                continue;
1094                            }
1095                        }
1096
1097                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1098                        gcurrentsqlstatement = lcnextsqlstatement;
1099                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1100
1101                        switch (gcurrentsqlstatement.sqlstatementtype) {
1102                            case sstmssqlcreateprocedure:
1103                            case sstmssqlcreatefunction:
1104                            case sstcreatetrigger:
1105                            case sstmssqlalterprocedure:
1106                            case sstmssqlalterfunction:
1107                            case sstmssqlaltertrigger: {
1108                                gst = EFindSqlStateType.ststoredprocedure;
1109                                break;
1110                            }
1111                            case sstmssqlbegintry:
1112                            case sstmssqlbegincatch: {
1113                                gst = EFindSqlStateType.sttrycatch;
1114                                lctrycatchlevel = 0;
1115                                break;
1116                            }
1117                            case sstmssqlgo: {
1118                                gst = EFindSqlStateType.stnormal;
1119                                break;
1120                            }
1121                            default: {
1122                                gst = EFindSqlStateType.stsql;
1123                                break;
1124                            }
1125                        }
1126
1127                    } else if ((ast.tokencode == TBaseType.rrw_begin)) {
1128                        if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1129                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) {
1130                            gst = EFindSqlStateType.stblock;
1131                            lcblocklevel = 0;
1132                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1133                        } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) {
1134                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1135                            gcurrentsqlstatement = new TMssqlBlock(vendor);
1136                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
1137                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1138                            gst = EFindSqlStateType.stblock;
1139                        } else {
1140                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1141                        }
1142                    } else if ((ast.tokencode == TBaseType.rrw_case)) {
1143                        case_end_nest++;
1144                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1145                    } else if ((ast.tokencode == TBaseType.rrw_end)) {
1146                        if (case_end_nest > 0) {
1147                            case_end_nest--;
1148                        }
1149                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1150                    } else if ((ast.tokencode == TBaseType.rrw_else)) {
1151                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1152                        if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
1153                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
1154                        ) && (case_end_nest == 0))
1155                            gcurrentsqlstatement.dummytag = 1;
1156                    } else {
1157                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1158                    }
1159                    break;
1160                }
1161                case ststoredprocedure: {
1162                    if (TBaseType.assigned(lcnextsqlstatement)) {
1163                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
1164                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1165                            gcurrentsqlstatement = lcnextsqlstatement;
1166                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1167                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1168                            gst = EFindSqlStateType.stnormal;
1169                        } else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn) {
1170                            gst = EFindSqlStateType.stprocedureWithReturn;
1171                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1172                            lcnextsqlstatement = null;
1173                        } else {
1174                            gst = EFindSqlStateType.ststoredprocedurebody;
1175                            gcurrentsqlstatement.sourcetokenlist.add(ast);
1176
1177                            lcnextsqlstatement = null;
1178                        }
1179                    }
1180
1181                    if (gst == EFindSqlStateType.ststoredprocedure) {
1182                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1183                        if (ast.tokencode == TBaseType.rrw_begin) {
1184                            gst = EFindSqlStateType.stblock;
1185                        }
1186                    }
1187                    break;
1188                }
1189                case ststoredprocedurebody: {
1190                    if (TBaseType.assigned(lcnextsqlstatement)) {
1191                        switch (lcnextsqlstatement.sqlstatementtype) {
1192                            case sstmssqlgo: {
1193                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1194                                gcurrentsqlstatement = lcnextsqlstatement;
1195                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1196                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1197                                gst = EFindSqlStateType.stnormal;
1198                                break;
1199                            }
1200                            case sstmssqlcreateprocedure:
1201                            case sstmssqlcreatefunction:
1202                            case sstcreatetrigger:
1203                            case sstmssqlalterprocedure:
1204                            case sstmssqlalterfunction:
1205                            case sstmssqlaltertrigger: {
1206                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1207                                gcurrentsqlstatement = lcnextsqlstatement;
1208                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1209                                gst = EFindSqlStateType.ststoredprocedure;
1210                                break;
1211                            }
1212                            case sstcreateview:
1213                            case sstcreatetable: {
1214
1215                                boolean readForNewStmt = false;
1216                                TSourceToken st1 = ast.searchToken(';', -1);
1217                                if (st1 != null) {
1218                                    TSourceToken st2 = ast.searchToken(TBaseType.rrw_end, -2);
1219                                    if (st2 != null) {
1220                                        readForNewStmt = true;
1221                                    }
1222                                }
1223
1224                                if (readForNewStmt) {
1225                                    onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1226                                    gcurrentsqlstatement = lcnextsqlstatement;
1227                                    gcurrentsqlstatement.sourcetokenlist.add(ast);
1228                                    gst = EFindSqlStateType.stsql;
1229                                } else {
1230                                    lcnextsqlstatement = null;
1231                                }
1232                                break;
1233                            }
1234                            case sstmssqlDropSecurityPolicy:
1235                            case sstmssqlAlterSecurityPolicy:
1236                            case sstmssqlCreateSecurityPolicy:
1237                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
1238                                gcurrentsqlstatement = lcnextsqlstatement;
1239                                gcurrentsqlstatement.sourcetokenlist.add(ast);
1240                                gst = EFindSqlStateType.stsql;
1241
1242                                break;
1243                            default: {
1244                                lcnextsqlstatement = null;
1245                                break;
1246                            }
1247                        }
1248                    }
1249
1250                    if (gst == EFindSqlStateType.ststoredprocedurebody)
1251                        gcurrentsqlstatement.sourcetokenlist.add(ast);
1252                }
1253                break;
1254            }
1255        }
1256
1257        //last statement
1258        if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) {
1259            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder);
1260        }
1261
1262        // Set results in builder
1263        builder.sqlStatements(this.sqlstatements);
1264        builder.errorCode(errorcount);
1265        builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount));
1266    }
1267}