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