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.TLexerSybase;
010import gudusoft.gsqlparser.TParserSybase;
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
040/**
041 * Sybase SQL parser implementation.
042 *
043 * <p>This parser handles Sybase-specific SQL syntax including:
044 * <ul>
045 *   <li>Sybase stored procedures with GO statement boundaries</li>
046 *   <li>Sybase BEGIN/END blocks</li>
047 *   <li>Sybase TRY/CATCH blocks</li>
048 *   <li>Sybase-specific statement types</li>
049 * </ul>
050 *
051 * <p><b>Design Notes:</b>
052 * <ul>
053 *   <li>Extends {@link AbstractSqlParser} using the template method pattern</li>
054 *   <li>Uses {@link TLexerSybase} for tokenization</li>
055 *   <li>Uses {@link TParserSybase} for parsing</li>
056 *   <li>Tokenization and statement extraction similar to MSSQL</li>
057 *   <li>Delimiter character: ';' for Sybase statements</li>
058 * </ul>
059 *
060 * @see SqlParser
061 * @see AbstractSqlParser
062 * @see TLexerSybase
063 * @see TParserSybase
064 * @since 3.2.0.0
065 */
066public class SybaseSqlParser extends AbstractSqlParser {
067
068    /**
069     * Construct Sybase SQL parser.
070     * <p>
071     * Configures the parser for Sybase with default delimiter (;).
072     */
073    public SybaseSqlParser() {
074        super(EDbVendor.dbvsybase);
075        this.delimiterChar = ';';
076        this.defaultDelimiterStr = ";";
077
078        // Create lexer once - will be reused for all parsing operations
079        this.flexer = new TLexerSybase();
080        this.flexer.delimiterchar = this.delimiterChar;
081        this.flexer.defaultDelimiterStr = this.defaultDelimiterStr;
082
083        // Set parent's lexer reference for shared tokenization logic
084        this.lexer = this.flexer;
085
086        // Create parser once - will be reused for all parsing operations
087        this.fparser = new TParserSybase(null);
088        this.fparser.lexer = this.flexer;
089    }
090
091    // ========== Parser Components ==========
092
093    /** The Sybase lexer used for tokenization */
094    public TLexerSybase flexer;
095
096    /** Sybase parser (for Sybase statements) */
097    private TParserSybase fparser;
098
099    /** Current statement being built during extraction */
100    private TCustomSqlStatement gcurrentsqlstatement;
101
102    // ========== AbstractSqlParser Abstract Methods Implementation ==========
103
104    /**
105     * Return the Sybase lexer instance.
106     */
107    @Override
108    protected TCustomLexer getLexer(ParserContext context) {
109        return this.flexer;
110    }
111
112    /**
113     * Return the Sybase parser instance with updated token list.
114     */
115    @Override
116    protected TCustomParser getParser(ParserContext context, TSourceTokenList tokens) {
117        this.fparser.sourcetokenlist = tokens;
118        return this.fparser;
119    }
120
121    /**
122     * Call Sybase-specific tokenization logic.
123     * <p>
124     * Sybase uses MSSQL-like tokenization.
125     */
126    @Override
127    protected void tokenizeVendorSql() {
128        dosybasesqltexttotokenlist();
129    }
130
131    /**
132     * Setup Sybase parser for raw statement extraction.
133     */
134    @Override
135    protected void setupVendorParsersForExtraction() {
136        this.fparser.sqlcmds = this.sqlcmds;
137        this.fparser.sourcetokenlist = this.sourcetokenlist;
138    }
139
140    /**
141     * Call Sybase-specific raw statement extraction logic.
142     */
143    @Override
144    protected void extractVendorRawStatements(SqlParseResult.Builder builder) {
145        dosybasegetrawsqlstatements(builder);
146    }
147
148    /**
149     * Perform full parsing of statements with syntax checking.
150     */
151    @Override
152    protected TStatementList performParsing(ParserContext context,
153                                           TCustomParser parser,
154                                           TCustomParser secondaryParser,
155                                           TSourceTokenList tokens,
156                                           TStatementList rawStatements) {
157        this.fparser = (TParserSybase) parser;
158        this.sourcetokenlist = tokens;
159        this.parserContext = context;
160        this.sqlstatements = rawStatements;
161
162        this.sqlcmds = SqlCmdsFactory.get(vendor);
163        this.fparser.sqlcmds = this.sqlcmds;
164
165        if (context != null && context.getGsqlparser() != null) {
166            TGSqlParser gsqlparser = (TGSqlParser) context.getGsqlparser();
167            this.frameStack = gsqlparser.getFrameStack();
168            this.fparser.getNf().setGsqlParser(gsqlparser);
169            this.globalContext = new TContext();
170            this.sqlEnv = new TSQLEnv(this.vendor) {
171                @Override
172                public void initSQLEnv() {
173                }
174            };
175            this.globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements);
176        } else {
177            initializeGlobalContext();
178        }
179
180        for (int i = 0; i < sqlstatements.size(); i++) {
181            TCustomSqlStatement stmt = sqlstatements.getRawSql(i);
182
183            try {
184                stmt.setFrameStack(frameStack);
185                int parseResult = stmt.parsestatement(null, false, context.isOnlyNeedRawParseTree());
186
187                boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE;
188                if (doRecover && ((parseResult != 0) || (stmt.getErrorCount() > 0))) {
189                    handleCreateTableErrorRecovery(stmt);
190                }
191
192                if ((parseResult != 0) || (stmt.getErrorCount() > 0)) {
193                    copyErrorsFromStatement(stmt);
194                }
195
196            } catch (Exception ex) {
197                handleStatementParsingException(stmt, i, ex);
198                continue;
199            }
200        }
201
202        if (globalFrame != null) {
203            globalFrame.popMeFromStack(frameStack);
204        }
205
206        return this.sqlstatements;
207    }
208
209    private void handleCreateTableErrorRecovery(TCustomSqlStatement stmt) {
210        if (((stmt.sqlstatementtype == ESqlStatementType.sstcreatetable)
211                || (stmt.sqlstatementtype == ESqlStatementType.sstcreateindex))
212                && (!TBaseType.c_createTableStrictParsing)) {
213
214            int nested = 0;
215            boolean isIgnore = false, isFoundIgnoreToken = false;
216            TSourceToken firstIgnoreToken = null;
217
218            for (int k = 0; k < stmt.sourcetokenlist.size(); k++) {
219                TSourceToken st = stmt.sourcetokenlist.get(k);
220                if (isIgnore) {
221                    if (st.issolidtoken() && (st.tokencode != ';')) {
222                        isFoundIgnoreToken = true;
223                        if (firstIgnoreToken == null) {
224                            firstIgnoreToken = st;
225                        }
226                    }
227                    if (st.tokencode != ';') {
228                        st.tokencode = TBaseType.sqlpluscmd;
229                    }
230                    continue;
231                }
232                if (st.tokencode == (int) ')') {
233                    nested--;
234                    if (nested == 0) {
235                        boolean isSelect = false;
236                        TSourceToken st1 = st.searchToken(TBaseType.rrw_as, 1);
237                        if (st1 != null) {
238                            TSourceToken st2 = st.searchToken((int) '(', 2);
239                            if (st2 != null) {
240                                TSourceToken st3 = st.searchToken(TBaseType.rrw_select, 3);
241                                isSelect = (st3 != null);
242                            }
243                        }
244                        if (!isSelect) isIgnore = true;
245                    }
246                } else if (st.tokencode == (int) '(') {
247                    nested++;
248                }
249            }
250
251            if (isFoundIgnoreToken) {
252                stmt.clearError();
253                stmt.parsestatement(null, false);
254            }
255        }
256    }
257
258    @Override
259    protected void performSemanticAnalysis(ParserContext context, TStatementList statements) {
260        if (context != null && context.getGsqlparser() != null) {
261            return;
262        }
263
264        if (getSyntaxErrors().isEmpty()) {
265            if (TBaseType.isEnableResolver2()) {
266                TSQLResolverConfig config = new TSQLResolverConfig();
267                config.setVendor(vendor);
268                TSQLResolver2 resolver2 = new TSQLResolver2(null, statements, config);
269                if (this.sqlEnv != null) {
270                    resolver2.setSqlEnv(this.sqlEnv);
271                }
272                resolver2.resolve();
273            } else if (TBaseType.isEnableResolver()) {
274                TSQLResolver resolver = new TSQLResolver(globalContext, statements);
275                resolver.resolve();
276            }
277        }
278    }
279
280    @Override
281    protected void performInterpreter(ParserContext context, TStatementList statements) {
282        if (TBaseType.ENABLE_INTERPRETER && getSyntaxErrors().isEmpty()) {
283            TLog.clearLogs();
284            TGlobalScope interpreterScope = new TGlobalScope(sqlEnv);
285            TLog.enableInterpreterLogOnly();
286            TASTEvaluator astEvaluator = new TASTEvaluator(statements, interpreterScope);
287            astEvaluator.eval();
288        }
289    }
290
291    // ========== Helper Methods ==========
292
293    /**
294     * Add token to current statement with proper statement linkage.
295     * This replicates TCustomSqlStatement.addtokentolist() behavior
296     * which sets st.stmt = this before adding.
297     */
298    private void addTokenToStatement(TSourceToken st) {
299        st.stmt = gcurrentsqlstatement;
300        gcurrentsqlstatement.sourcetokenlist.add(st);
301    }
302
303    // ========== Sybase-Specific Tokenization ==========
304
305    /**
306     * Sybase-specific tokenization logic.
307     * <p>
308     * Sybase uses MSSQL-like tokenization.
309     * Migrated from TGSqlParser.dosybasesqltexttotokenlist()
310     */
311    private void dosybasesqltexttotokenlist() {
312        TSourceToken lcprevtoken = null;
313        int lcsteps = 0;
314        TSourceToken asourcetoken, lctoken, lctoken2, lctoken3;
315        int yychar;
316        boolean iskeywordgo;
317
318        asourcetoken = getanewsourcetoken();
319
320        if (asourcetoken == null) return;
321
322        yychar = asourcetoken.tokencode;
323
324        boolean lcinopenrowset = false;
325        int lcnested = 0;
326
327        while (yychar > 0) {
328
329            if (asourcetoken.tokencode == TBaseType.rrw_openrowset) {
330                lcinopenrowset = true;
331                lcnested = 0;
332            } else if (asourcetoken.tokentype == ETokenType.ttleftparenthesis) {
333                if ((lcsteps > 0) && TBaseType.assigned(lcprevtoken)) {
334                    if (lcprevtoken.tokencode == TBaseType.rrw_primary) {
335                        lcprevtoken.tokencode = TBaseType.rrw_select - 2;
336                        checkconstarinttoken(lcprevtoken);
337                    } else if (lcprevtoken.tokencode == TBaseType.rrw_foreign) {
338                        lcprevtoken.tokencode = TBaseType.rrw_select - 4;
339                        checkconstarinttoken(lcprevtoken);
340                    } else if (lcprevtoken.tokencode == TBaseType.rrw_unique) {
341                        lcprevtoken.tokencode = TBaseType.rrw_select - 1;
342                        checkconstarinttoken(lcprevtoken);
343                    }
344                    lcprevtoken = null;
345                    lcsteps = 0;
346                }
347
348                if (lcinopenrowset)
349                    lcnested++;
350            } else if (asourcetoken.tokentype == ETokenType.ttrightparenthesis) {
351                if (lcinopenrowset) {
352                    if ((lcnested > 0))
353                        lcnested--;
354                    if (lcnested == 0)
355                        lcinopenrowset = false;
356                }
357            } else if (asourcetoken.tokentype == ETokenType.ttsemicolon) {
358                if (lcinopenrowset) {
359                    asourcetoken.tokentype = ETokenType.ttsemicolon2;
360                } else {
361                    lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin, -1);
362                    if (lctoken2 != null) {
363                        asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
364                        asourcetoken.tokentype = ETokenType.ttsemicolon3;
365                    } else {
366                        lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try, -1);
367                        if (lctoken2 == null) {
368                            lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch, -1);
369                        }
370                        if (lctoken2 != null) {
371                            lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin, -2);
372                            if (lctoken3 != null) {
373                                asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN;
374                                asourcetoken.tokentype = ETokenType.ttsemicolon3;
375                            }
376                        }
377                    }
378                }
379            } else if (asourcetoken.tokentype == ETokenType.ttperiod) {
380                lctoken = getprevtoken(asourcetoken);
381                if (TBaseType.assigned(lctoken)) {
382                    if (lctoken.tokencode == TBaseType.rrw_go) {
383                        lctoken.tokencode = TBaseType.ident;
384                        lctoken.tokentype = ETokenType.ttidentifier;
385                    }
386                }
387            } else if (asourcetoken.tokencode == TBaseType.rrw_table) {
388                lctoken = getprevtoken(asourcetoken);
389                if (TBaseType.assigned(lctoken)) {
390                    if (lctoken.tokencode == TBaseType.rrw_lock) {
391                        lctoken.tokencode = TBaseType.rw_locktable;
392                    }
393                }
394            } else if (asourcetoken.tokencode == TBaseType.rrw_sybase_isolation) {
395                // AT ISOLATION clause - change 'at' token code for grammar recognition
396                lctoken = getprevtoken(asourcetoken);
397                if (TBaseType.assigned(lctoken)) {
398                    if (lctoken.tokencode == TBaseType.rrw_sybase_at) {
399                        lctoken.tokencode = TBaseType.rw_sybase_at1;
400                    }
401                }
402            } else if (asourcetoken.tokencode == TBaseType.rrw_update) {
403                // UPDATE in create trigger context
404                lctoken = getprevtoken(asourcetoken);
405                if (TBaseType.assigned(lctoken)) {
406                    if ((lctoken.tokencode == TBaseType.rrw_not)
407                            || (lctoken.tokencode == TBaseType.rrw_and)
408                            || (lctoken.tokencode == TBaseType.rrw_or)
409                            || (lctoken.tokencode == TBaseType.rrw_if)
410                    ) {
411                        // this is update(column) in create trigger
412                        asourcetoken.tokencode = TBaseType.rw_sybase_update1;
413                    }
414                }
415            } else if (asourcetoken.tokencode == TBaseType.rrw_go) {
416                iskeywordgo = true;
417                lctoken = getprevtoken(asourcetoken);
418                if (TBaseType.assigned(lctoken)) {
419                    if ((lctoken.lineNo == asourcetoken.lineNo) && (lctoken.tokencode != ';')) {
420                        iskeywordgo = false;
421                    }
422                }
423
424                if (iskeywordgo) {
425                    lcinopenrowset = false;
426                    lcnested = 0;
427                    lcprevtoken = asourcetoken;
428                } else {
429                    asourcetoken.tokencode = TBaseType.ident;
430                    asourcetoken.tokentype = ETokenType.ttidentifier;
431                }
432            } else if (asourcetoken.tokencode == TBaseType.rrw_primary) {
433                lcsteps = 2;
434                lcprevtoken = asourcetoken;
435            } else if (asourcetoken.tokencode == TBaseType.rrw_foreign) {
436                lcsteps = 2;
437                lcprevtoken = asourcetoken;
438            } else if (asourcetoken.tokencode == TBaseType.rrw_unique) {
439                lcsteps = 1;
440                lcprevtoken = asourcetoken;
441            } else if (asourcetoken.issolidtoken()) {
442                if (lcsteps > 0) {
443                    if (!(TBaseType.mysametext("clustered", asourcetoken.toString())
444                            || TBaseType.mysametext("nonclustered", asourcetoken.toString())
445                            || TBaseType.mysametext("hash", asourcetoken.toString())
446                    ))
447                        lcsteps--;
448                }
449            }
450
451            sourcetokenlist.add(asourcetoken);
452
453            asourcetoken = getanewsourcetoken();
454            if (asourcetoken == null) break;
455            yychar = asourcetoken.tokencode;
456        }
457    }
458
459    private TSourceToken getprevtoken(TSourceToken ptoken) {
460        TSourceTokenList lcstlist = ptoken.container;
461        if (TBaseType.assigned(lcstlist)) {
462            if ((ptoken.posinlist > 0) && (lcstlist.size() > ptoken.posinlist - 1)) {
463                if (!((lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttwhitespace)
464                        || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttreturn)
465                        || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttsimplecomment)
466                        || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttbracketedcomment)
467                )) {
468                    return lcstlist.get(ptoken.posinlist - 1);
469                } else {
470                    return lcstlist.nextsolidtoken(ptoken.posinlist - 1, -1, false);
471                }
472            }
473        }
474        return null;
475    }
476
477    private void checkconstarinttoken(TSourceToken token) {
478        TSourceTokenList lcStList = token.container;
479        if (TBaseType.assigned(lcStList)) {
480            TSourceToken lcPPToken = lcStList.nextsolidtoken(token.posinlist, -2, false);
481            if (TBaseType.assigned(lcPPToken)) {
482                if (lcPPToken.tokencode == flexer.getkeywordvalue("constraint")) {
483                    lcPPToken.tokencode = TBaseType.rw_constraint2;
484                }
485            }
486        }
487    }
488
489    // ========== Sybase-Specific Raw Statement Extraction ==========
490
491    /**
492     * Sybase-specific raw statement extraction logic.
493     * <p>
494     * Migrated from TGSqlParser.dosybasegetrawsqlstatements()
495     */
496    private void dosybasegetrawsqlstatements(SqlParseResult.Builder builder) {
497        int errorcount = 0;
498        int case_end_nest = 0;
499
500        if (TBaseType.assigned(sqlstatements)) sqlstatements.clear();
501        if (!TBaseType.assigned(sourcetokenlist)) {
502            builder.errorCode(-1);
503            builder.errorMessage("Source token list is null");
504            return;
505        }
506
507        gcurrentsqlstatement = null;
508        EFindSqlStateType gst = EFindSqlStateType.stnormal;
509        int lcblocklevel = 0;
510        int lctrycatchlevel = 0;
511        TSourceToken lcprevsolidtoken = null, lcnextsolidtoken, lcnnextsolidtoken;
512        TSourceToken ast = null;
513        int i;
514        boolean lcisendconversation, lcstillinsql;
515
516        for (i = 0; i < sourcetokenlist.size(); i++) {
517
518            if ((ast != null) && (ast.issolidtoken()))
519                lcprevsolidtoken = ast;
520
521            ast = sourcetokenlist.get(i);
522            sourcetokenlist.curpos = i;
523            if (ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement) {
524                addTokenToStatement(ast);
525                continue;
526            }
527
528            if (gst == EFindSqlStateType.ststoredprocedurebody) {
529                if (!((ast.tokencode == TBaseType.rrw_go)
530                        || (ast.tokencode == TBaseType.rrw_create)
531                        || (ast.tokencode == TBaseType.rrw_alter))) {
532                    addTokenToStatement(ast);
533                    continue;
534                }
535            }
536
537            TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement);
538
539            switch (gst) {
540                case sterror: {
541                    if (TBaseType.assigned(lcnextsqlstatement)) {
542                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
543                        gcurrentsqlstatement = lcnextsqlstatement;
544                        addTokenToStatement(ast);
545                        gst = EFindSqlStateType.stsql;
546                    } else if ((ast.tokentype == ETokenType.ttsemicolon)) {
547                        addTokenToStatement(ast);
548                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
549                        gst = EFindSqlStateType.stnormal;
550                    } else {
551                        addTokenToStatement(ast);
552                    }
553                    break;
554                }
555                case stnormal: {
556                    if ((ast.tokencode == TBaseType.cmtdoublehyphen)
557                            || (ast.tokencode == TBaseType.cmtslashstar)
558                            || (ast.tokencode == TBaseType.lexspace)
559                            || (ast.tokencode == TBaseType.lexnewline)
560                            || (ast.tokentype == ETokenType.ttsemicolon)) {
561                        if (TBaseType.assigned(gcurrentsqlstatement)) {
562                            addTokenToStatement(ast);
563                        }
564
565                        if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) {
566                            if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) {
567                                ast.tokentype = ETokenType.ttsimplecomment;
568                                ast.tokencode = TBaseType.cmtdoublehyphen;
569                            }
570                        }
571
572                        continue;
573                    }
574
575                    gcurrentsqlstatement = lcnextsqlstatement;
576
577                    if (TBaseType.assigned(gcurrentsqlstatement)) {
578                        switch (gcurrentsqlstatement.sqlstatementtype) {
579                            case sstmssqlcreateprocedure:
580                            case sstmssqlcreatefunction:
581                            case sstcreatetrigger:
582                            case sstmssqlalterprocedure:
583                            case sstmssqlalterfunction:
584                            case sstmssqlaltertrigger: {
585                                addTokenToStatement(ast);
586                                gst = EFindSqlStateType.ststoredprocedure;
587                                break;
588                            }
589                            case sstmssqlbegintry:
590                            case sstmssqlbegincatch: {
591                                addTokenToStatement(ast);
592                                gst = EFindSqlStateType.sttrycatch;
593                                lctrycatchlevel = 0;
594                                break;
595                            }
596                            case sstmssqlgo: {
597                                addTokenToStatement(ast);
598                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
599                                gst = EFindSqlStateType.stnormal;
600                                break;
601                            }
602                            default: {
603                                addTokenToStatement(ast);
604                                if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqllabel) {
605                                    onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
606                                    gst = EFindSqlStateType.stnormal;
607                                } else {
608                                    gst = EFindSqlStateType.stsql;
609                                }
610                                break;
611                            }
612                        }
613                    } else {
614                        if (ast.tokencode == TBaseType.rrw_begin) {
615                            gcurrentsqlstatement = new TMssqlBlock(vendor);
616                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
617                            addTokenToStatement(ast);
618                            gst = EFindSqlStateType.stblock;
619                        } else {
620                            if (sqlstatements.size() == 0) {
621                                gst = EFindSqlStateType.stsql;
622                                gcurrentsqlstatement = new TMssqlExecute(vendor);
623                                ast.tokencode = TBaseType.rrw_sybase_exce_proc_name;
624                                addTokenToStatement(ast);
625                            } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) {
626                                gst = EFindSqlStateType.stsql;
627                                gcurrentsqlstatement = new TMssqlExecute(vendor);
628                                ast.tokencode = TBaseType.rrw_sybase_exce_proc_name;
629                                addTokenToStatement(ast);
630                            }
631                        }
632                    }
633
634                    if (!TBaseType.assigned(gcurrentsqlstatement)) {
635                        this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo)
636                                , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist));
637
638                        ast.tokentype = ETokenType.tttokenlizererrortoken;
639                        gst = EFindSqlStateType.sterror;
640
641                        gcurrentsqlstatement = new TUnknownSqlStatement(vendor);
642                        gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid;
643                        addTokenToStatement(ast);
644                    }
645                    break;
646                }
647                case stblock: {
648                    if (TBaseType.assigned(lcnextsqlstatement)) {
649                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
650                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
651                            gcurrentsqlstatement = lcnextsqlstatement;
652                            addTokenToStatement(ast);
653                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
654                            gst = EFindSqlStateType.stnormal;
655                        } else {
656                            lcnextsqlstatement = null;
657                        }
658                    }
659
660                    if (gst == EFindSqlStateType.stblock) {
661                        addTokenToStatement(ast);
662                        if (ast.tokencode == TBaseType.rrw_begin) {
663                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
664                            if (TBaseType.assigned(lcnextsolidtoken)) {
665                                if (!(TBaseType.mysametext(lcnextsolidtoken.getAstext(), "tran")
666                                        || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "transaction")
667                                        || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "distributed")
668                                        || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "dialog")
669                                        || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "conversation")
670                                ))
671                                    lcblocklevel++;
672                            } else
673                                lcblocklevel++;
674
675                        } else if (ast.tokencode == TBaseType.rrw_case)
676                            lcblocklevel++;
677                        else if (ast.tokencode == TBaseType.rrw_end) {
678
679                            lcisendconversation = false;
680
681                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
682                            if (TBaseType.assigned(lcnextsolidtoken)) {
683                                if (lcnextsolidtoken.tokencode == flexer.getkeywordvalue("CONVERSATION"))
684                                    lcisendconversation = true;
685                            }
686
687                            if (!lcisendconversation) {
688
689                                if (lcblocklevel == 0) {
690                                    if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
691                                        if (TBaseType.assigned(lcnextsolidtoken)) {
692                                            if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
693                                                gst = EFindSqlStateType.stsql;
694                                            } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) {
695                                                lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false);
696                                                if (TBaseType.assigned(lcnnextsolidtoken)) {
697                                                    if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) {
698                                                        gst = EFindSqlStateType.stsql;
699                                                    }
700                                                }
701                                            }
702                                        }
703                                    }
704
705                                    if (gst != EFindSqlStateType.stsql) {
706                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
707                                        gst = EFindSqlStateType.stnormal;
708                                    }
709
710                                } else {
711                                    lcblocklevel--;
712                                }
713
714                            }
715                        }
716                    }
717                    break;
718                }
719                case sttrycatch: {
720
721                    if (TBaseType.assigned(lcnextsqlstatement)) {
722                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
723                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
724                            gcurrentsqlstatement = lcnextsqlstatement;
725                            addTokenToStatement(ast);
726                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
727                            gst = EFindSqlStateType.stnormal;
728                        } else {
729                            if (
730                                    (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)
731                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
732                            )
733                                lctrycatchlevel++;
734                            lcnextsqlstatement = null;
735                        }
736                    }
737
738                    if (gst == EFindSqlStateType.sttrycatch) {
739                        addTokenToStatement(ast);
740                        if ((ast.tokencode == TBaseType.rrw_try) ||
741                                (ast.tokencode == TBaseType.rrw_catch)) {
742                            if (TBaseType.assigned(lcprevsolidtoken)) {
743                                if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) {
744                                    if (lctrycatchlevel == 0) {
745                                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
746                                        gst = EFindSqlStateType.stnormal;
747                                    } else
748                                        lctrycatchlevel--;
749                                }
750                            }
751                        }
752                    }
753                    break;
754                }
755                case stsql: {
756                    if ((ast.tokentype == ETokenType.ttsemicolon)) {
757                        lcstillinsql = false;
758                        if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) {
759                            lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false);
760                            if (TBaseType.assigned(lcnextsolidtoken)) {
761                                if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) {
762                                    addTokenToStatement(ast);
763                                    lcstillinsql = true;
764                                }
765
766                            }
767                        }
768
769                        if (!lcstillinsql) {
770                            gst = EFindSqlStateType.stnormal;
771                            addTokenToStatement(ast);
772                            gcurrentsqlstatement.semicolonended = ast;
773                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
774                        }
775
776                    } else if (TBaseType.assigned(lcnextsqlstatement)) {
777
778                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
779                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
780                            gcurrentsqlstatement = lcnextsqlstatement;
781                            addTokenToStatement(ast);
782                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
783                            gst = EFindSqlStateType.stnormal;
784                            continue;
785                        }
786
787                        switch (gcurrentsqlstatement.sqlstatementtype) {
788                            case sstmssqlif:
789                            case sstmssqlwhile: {
790                                if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch)
791                                        || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) {
792                                    addTokenToStatement(ast);
793                                    gst = EFindSqlStateType.stblock;
794                                    lcblocklevel = 1;
795                                    lcnextsqlstatement = null;
796                                    continue;
797
798                                } else if (gcurrentsqlstatement.dummytag == 1) {
799                                    addTokenToStatement(ast);
800
801                                    if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
802                                            || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile))
803                                        gcurrentsqlstatement.dummytag = 1;
804                                    else
805                                        gcurrentsqlstatement.dummytag = 0;
806
807
808                                    lcnextsqlstatement = null;
809                                    continue;
810                                }
811                                break;
812                            }
813                            case sstmssqlalterqueue: {
814                                if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) {
815                                    addTokenToStatement(ast);
816
817                                    lcnextsqlstatement = null;
818                                    continue;
819
820                                }
821                                break;
822                            }
823                            case sstmssqlcreateschema: {
824                                addTokenToStatement(ast);
825                                lcnextsqlstatement = null;
826                                continue;
827                            }
828                        }
829
830                        onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
831                        gcurrentsqlstatement = lcnextsqlstatement;
832                        addTokenToStatement(ast);
833
834                        switch (gcurrentsqlstatement.sqlstatementtype) {
835                            case sstmssqlcreateprocedure:
836                            case sstmssqlcreatefunction:
837                            case sstcreatetrigger:
838                            case sstmssqlalterprocedure:
839                            case sstmssqlalterfunction:
840                            case sstmssqlaltertrigger: {
841                                gst = EFindSqlStateType.ststoredprocedure;
842                                break;
843                            }
844                            case sstmssqlbegintry:
845                            case sstmssqlbegincatch: {
846                                gst = EFindSqlStateType.sttrycatch;
847                                lctrycatchlevel = 0;
848                                break;
849                            }
850                            case sstmssqlgo: {
851                                gst = EFindSqlStateType.stnormal;
852                                break;
853                            }
854                            default: {
855                                gst = EFindSqlStateType.stsql;
856                                break;
857                            }
858                        }
859
860                    } else if ((ast.tokencode == TBaseType.rrw_begin)) {
861                        if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
862                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) {
863                            gst = EFindSqlStateType.stblock;
864                            lcblocklevel = 0;
865                            addTokenToStatement(ast);
866                        } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) {
867                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
868                            gcurrentsqlstatement = new TMssqlBlock(vendor);
869                            gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock;
870                            addTokenToStatement(ast);
871                            gst = EFindSqlStateType.stblock;
872                        } else {
873                            addTokenToStatement(ast);
874                        }
875                    } else if ((ast.tokencode == TBaseType.rrw_case)) {
876                        case_end_nest++;
877                        addTokenToStatement(ast);
878                    } else if ((ast.tokencode == TBaseType.rrw_end)) {
879                        if (case_end_nest > 0) {
880                            case_end_nest--;
881                        }
882                        addTokenToStatement(ast);
883                    } else if ((ast.tokencode == TBaseType.rrw_else)) {
884                        addTokenToStatement(ast);
885                        if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif)
886                                || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)
887                        ) && (case_end_nest == 0))
888                            gcurrentsqlstatement.dummytag = 1;
889                    } else {
890                        addTokenToStatement(ast);
891                        if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlset) {
892                            if (ast.tokencode == TBaseType.rrw_on) {
893                                gst = EFindSqlStateType.stnormal;
894                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
895                            }
896                        }
897                    }
898                    break;
899                }
900                case ststoredprocedure: {
901                    if (TBaseType.assigned(lcnextsqlstatement)) {
902                        if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) {
903                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
904                            gcurrentsqlstatement = lcnextsqlstatement;
905                            addTokenToStatement(ast);
906                            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
907                            gst = EFindSqlStateType.stnormal;
908                        } else {
909                            gst = EFindSqlStateType.ststoredprocedurebody;
910                            addTokenToStatement(ast);
911
912                            lcnextsqlstatement = null;
913                        }
914                    }
915
916                    if (gst == EFindSqlStateType.ststoredprocedure) {
917                        addTokenToStatement(ast);
918                        if (ast.tokencode == TBaseType.rrw_begin) {
919                            gst = EFindSqlStateType.stblock;
920                        }
921                    }
922                    break;
923                }
924                case ststoredprocedurebody: {
925                    if (TBaseType.assigned(lcnextsqlstatement)) {
926                        switch (lcnextsqlstatement.sqlstatementtype) {
927                            case sstmssqlgo: {
928                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
929                                gcurrentsqlstatement = lcnextsqlstatement;
930                                addTokenToStatement(ast);
931                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
932                                gst = EFindSqlStateType.stnormal;
933                                break;
934                            }
935                            case sstmssqlcreateprocedure:
936                            case sstmssqlcreatefunction:
937                            case sstcreatetrigger:
938                            case sstmssqlalterprocedure:
939                            case sstmssqlalterfunction:
940                            case sstmssqlaltertrigger: {
941                                onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder);
942                                gcurrentsqlstatement = lcnextsqlstatement;
943                                addTokenToStatement(ast);
944                                gst = EFindSqlStateType.ststoredprocedure;
945                                break;
946                            }
947                            default: {
948                                lcnextsqlstatement = null;
949                                break;
950                            }
951                        }
952                    }
953
954                    if (gst == EFindSqlStateType.ststoredprocedurebody)
955                        addTokenToStatement(ast);
956                }
957                break;
958            }
959        }
960
961        // last statement
962        if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) {
963            onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder);
964        }
965
966        builder.sqlStatements(this.sqlstatements);
967        builder.errorCode(errorcount);
968        builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount));
969    }
970}