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 // Watcom / SAP IQ / SQL Anywhere `IF cond THEN ... END IF` tracking. 500 // `lcwatcomIfNest` counts open IF...THEN blocks awaiting END IF or 501 // ENDIF inside a BEGIN/END block. `lcwhenPending` counts WHEN tokens 502 // awaiting their matching THEN so that CASE WHEN ... THEN, MERGE 503 // WHEN ... THEN and EXCEPTION WHEN ... THEN do not look like Watcom 504 // IF openers. The counters are only used in the stblock state — at 505 // top level we still rely on the standard statement-splitter path. 506 int lcwatcomIfNest = 0; 507 int lcwhenPending = 0; 508 509 if (TBaseType.assigned(sqlstatements)) sqlstatements.clear(); 510 if (!TBaseType.assigned(sourcetokenlist)) { 511 builder.errorCode(-1); 512 builder.errorMessage("Source token list is null"); 513 return; 514 } 515 516 gcurrentsqlstatement = null; 517 EFindSqlStateType gst = EFindSqlStateType.stnormal; 518 int lcblocklevel = 0; 519 int lctrycatchlevel = 0; 520 TSourceToken lcprevsolidtoken = null, lcnextsolidtoken, lcnnextsolidtoken; 521 TSourceToken ast = null; 522 int i; 523 boolean lcisendconversation, lcstillinsql; 524 525 for (i = 0; i < sourcetokenlist.size(); i++) { 526 527 if ((ast != null) && (ast.issolidtoken())) 528 lcprevsolidtoken = ast; 529 530 ast = sourcetokenlist.get(i); 531 sourcetokenlist.curpos = i; 532 if (ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement) { 533 addTokenToStatement(ast); 534 continue; 535 } 536 537 if (gst == EFindSqlStateType.ststoredprocedurebody) { 538 if (!((ast.tokencode == TBaseType.rrw_go) 539 || (ast.tokencode == TBaseType.rrw_create) 540 || (ast.tokencode == TBaseType.rrw_alter))) { 541 addTokenToStatement(ast); 542 continue; 543 } 544 } 545 546 TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement); 547 548 switch (gst) { 549 case sterror: { 550 if (TBaseType.assigned(lcnextsqlstatement)) { 551 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 552 gcurrentsqlstatement = lcnextsqlstatement; 553 addTokenToStatement(ast); 554 gst = EFindSqlStateType.stsql; 555 } else if ((ast.tokentype == ETokenType.ttsemicolon)) { 556 addTokenToStatement(ast); 557 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 558 gst = EFindSqlStateType.stnormal; 559 } else { 560 addTokenToStatement(ast); 561 } 562 break; 563 } 564 case stnormal: { 565 if ((ast.tokencode == TBaseType.cmtdoublehyphen) 566 || (ast.tokencode == TBaseType.cmtslashstar) 567 || (ast.tokencode == TBaseType.lexspace) 568 || (ast.tokencode == TBaseType.lexnewline) 569 || (ast.tokentype == ETokenType.ttsemicolon)) { 570 if (TBaseType.assigned(gcurrentsqlstatement)) { 571 addTokenToStatement(ast); 572 } 573 574 if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) { 575 if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) { 576 ast.tokentype = ETokenType.ttsimplecomment; 577 ast.tokencode = TBaseType.cmtdoublehyphen; 578 } 579 } 580 581 continue; 582 } 583 584 gcurrentsqlstatement = lcnextsqlstatement; 585 586 if (TBaseType.assigned(gcurrentsqlstatement)) { 587 switch (gcurrentsqlstatement.sqlstatementtype) { 588 case sstmssqlcreateprocedure: 589 case sstmssqlcreatefunction: 590 case sstcreatetrigger: 591 case sstmssqlalterprocedure: 592 case sstmssqlalterfunction: 593 case sstmssqlaltertrigger: { 594 addTokenToStatement(ast); 595 gst = EFindSqlStateType.ststoredprocedure; 596 break; 597 } 598 case sstmssqlbegintry: 599 case sstmssqlbegincatch: { 600 addTokenToStatement(ast); 601 gst = EFindSqlStateType.sttrycatch; 602 lctrycatchlevel = 0; 603 break; 604 } 605 case sstmssqlgo: { 606 addTokenToStatement(ast); 607 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 608 gst = EFindSqlStateType.stnormal; 609 break; 610 } 611 default: { 612 addTokenToStatement(ast); 613 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqllabel) { 614 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 615 gst = EFindSqlStateType.stnormal; 616 } else { 617 gst = EFindSqlStateType.stsql; 618 } 619 break; 620 } 621 } 622 } else { 623 if (ast.tokencode == TBaseType.rrw_begin) { 624 gcurrentsqlstatement = new TMssqlBlock(vendor); 625 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 626 addTokenToStatement(ast); 627 gst = EFindSqlStateType.stblock; 628 } else { 629 if (sqlstatements.size() == 0) { 630 gst = EFindSqlStateType.stsql; 631 gcurrentsqlstatement = new TMssqlExecute(vendor); 632 ast.tokencode = TBaseType.rrw_sybase_exce_proc_name; 633 addTokenToStatement(ast); 634 } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) { 635 gst = EFindSqlStateType.stsql; 636 gcurrentsqlstatement = new TMssqlExecute(vendor); 637 ast.tokencode = TBaseType.rrw_sybase_exce_proc_name; 638 addTokenToStatement(ast); 639 } 640 } 641 } 642 643 if (!TBaseType.assigned(gcurrentsqlstatement)) { 644 this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo) 645 , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist)); 646 647 ast.tokentype = ETokenType.tttokenlizererrortoken; 648 gst = EFindSqlStateType.sterror; 649 650 gcurrentsqlstatement = new TUnknownSqlStatement(vendor); 651 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 652 addTokenToStatement(ast); 653 } 654 break; 655 } 656 case stblock: { 657 if (TBaseType.assigned(lcnextsqlstatement)) { 658 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 659 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 660 gcurrentsqlstatement = lcnextsqlstatement; 661 addTokenToStatement(ast); 662 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 663 gst = EFindSqlStateType.stnormal; 664 } else { 665 lcnextsqlstatement = null; 666 } 667 } 668 669 if (gst == EFindSqlStateType.stblock) { 670 addTokenToStatement(ast); 671 if (ast.tokencode == TBaseType.rrw_begin) { 672 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 673 if (TBaseType.assigned(lcnextsolidtoken)) { 674 if (!(TBaseType.mysametext(lcnextsolidtoken.getAstext(), "tran") 675 || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "transaction") 676 || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "distributed") 677 || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "dialog") 678 || TBaseType.mysametext(lcnextsolidtoken.getAstext(), "conversation") 679 )) 680 lcblocklevel++; 681 } else 682 lcblocklevel++; 683 684 } else if (ast.tokencode == TBaseType.rrw_case) 685 lcblocklevel++; 686 else if (ast.tokencode == TBaseType.rrw_when) { 687 // Each WHEN expects a matching THEN (CASE, MERGE, 688 // EXCEPTION). Track so that THEN does not get 689 // confused with the Watcom IF...THEN opener. 690 lcwhenPending++; 691 } else if (ast.tokencode == TBaseType.rrw_then) { 692 if (lcwhenPending > 0) 693 lcwhenPending--; 694 else 695 lcwatcomIfNest++; 696 } else if (ast.tokencode == flexer.getkeywordvalue("ENDIF")) { 697 // One-word ENDIF closes a Watcom IF if one is open. 698 if (lcwatcomIfNest > 0) 699 lcwatcomIfNest--; 700 } else if (ast.tokencode == TBaseType.rrw_end) { 701 702 lcisendconversation = false; 703 // Watcom/SQL Anywhere/Sybase IQ: `END IF` closes a 704 // Watcom IF statement only when there is an open 705 // IF...THEN to match. Without that match, `END` 706 // followed by `IF` is just a block-close followed 707 // by a new T-SQL `IF` statement (semicolons are 708 // optional in Sybase/T-SQL), so we must still 709 // decrement the block level normally. 710 boolean lcisendif = false; 711 712 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 713 if (TBaseType.assigned(lcnextsolidtoken)) { 714 if (lcnextsolidtoken.tokencode == flexer.getkeywordvalue("CONVERSATION")) 715 lcisendconversation = true; 716 else if (lcnextsolidtoken.tokencode == TBaseType.rrw_if 717 && lcwatcomIfNest > 0) { 718 lcisendif = true; 719 lcwatcomIfNest--; 720 } 721 } 722 723 if (!lcisendconversation && !lcisendif) { 724 725 if (lcblocklevel == 0) { 726 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 727 if (TBaseType.assigned(lcnextsolidtoken)) { 728 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 729 gst = EFindSqlStateType.stsql; 730 } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) { 731 lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false); 732 if (TBaseType.assigned(lcnnextsolidtoken)) { 733 if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) { 734 gst = EFindSqlStateType.stsql; 735 } 736 } 737 } 738 } 739 } 740 741 if (gst != EFindSqlStateType.stsql) { 742 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 743 gst = EFindSqlStateType.stnormal; 744 } 745 746 } else { 747 lcblocklevel--; 748 } 749 750 } 751 } 752 } 753 break; 754 } 755 case sttrycatch: { 756 757 if (TBaseType.assigned(lcnextsqlstatement)) { 758 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 759 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 760 gcurrentsqlstatement = lcnextsqlstatement; 761 addTokenToStatement(ast); 762 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 763 gst = EFindSqlStateType.stnormal; 764 } else { 765 if ( 766 (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry) 767 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 768 ) 769 lctrycatchlevel++; 770 lcnextsqlstatement = null; 771 } 772 } 773 774 if (gst == EFindSqlStateType.sttrycatch) { 775 addTokenToStatement(ast); 776 if ((ast.tokencode == TBaseType.rrw_try) || 777 (ast.tokencode == TBaseType.rrw_catch)) { 778 if (TBaseType.assigned(lcprevsolidtoken)) { 779 if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) { 780 if (lctrycatchlevel == 0) { 781 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 782 gst = EFindSqlStateType.stnormal; 783 } else 784 lctrycatchlevel--; 785 } 786 } 787 } 788 } 789 break; 790 } 791 case stsql: { 792 if ((ast.tokentype == ETokenType.ttsemicolon)) { 793 lcstillinsql = false; 794 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 795 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 796 if (TBaseType.assigned(lcnextsolidtoken)) { 797 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 798 addTokenToStatement(ast); 799 lcstillinsql = true; 800 } 801 802 } 803 } 804 805 if (!lcstillinsql) { 806 gst = EFindSqlStateType.stnormal; 807 addTokenToStatement(ast); 808 gcurrentsqlstatement.semicolonended = ast; 809 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 810 } 811 812 } else if (TBaseType.assigned(lcnextsqlstatement)) { 813 814 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 815 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 816 gcurrentsqlstatement = lcnextsqlstatement; 817 addTokenToStatement(ast); 818 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 819 gst = EFindSqlStateType.stnormal; 820 continue; 821 } 822 823 switch (gcurrentsqlstatement.sqlstatementtype) { 824 case sstmssqlif: 825 case sstmssqlwhile: { 826 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 827 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) { 828 addTokenToStatement(ast); 829 gst = EFindSqlStateType.stblock; 830 lcblocklevel = 1; 831 lcnextsqlstatement = null; 832 continue; 833 834 } else if (gcurrentsqlstatement.dummytag == 1) { 835 addTokenToStatement(ast); 836 837 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 838 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) 839 gcurrentsqlstatement.dummytag = 1; 840 else 841 gcurrentsqlstatement.dummytag = 0; 842 843 844 lcnextsqlstatement = null; 845 continue; 846 } 847 break; 848 } 849 case sstmssqlalterqueue: { 850 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) { 851 addTokenToStatement(ast); 852 853 lcnextsqlstatement = null; 854 continue; 855 856 } 857 break; 858 } 859 case sstmssqlcreateschema: { 860 addTokenToStatement(ast); 861 lcnextsqlstatement = null; 862 continue; 863 } 864 } 865 866 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 867 gcurrentsqlstatement = lcnextsqlstatement; 868 addTokenToStatement(ast); 869 870 switch (gcurrentsqlstatement.sqlstatementtype) { 871 case sstmssqlcreateprocedure: 872 case sstmssqlcreatefunction: 873 case sstcreatetrigger: 874 case sstmssqlalterprocedure: 875 case sstmssqlalterfunction: 876 case sstmssqlaltertrigger: { 877 gst = EFindSqlStateType.ststoredprocedure; 878 break; 879 } 880 case sstmssqlbegintry: 881 case sstmssqlbegincatch: { 882 gst = EFindSqlStateType.sttrycatch; 883 lctrycatchlevel = 0; 884 break; 885 } 886 case sstmssqlgo: { 887 gst = EFindSqlStateType.stnormal; 888 break; 889 } 890 default: { 891 gst = EFindSqlStateType.stsql; 892 break; 893 } 894 } 895 896 } else if ((ast.tokencode == TBaseType.rrw_begin)) { 897 if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 898 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) { 899 gst = EFindSqlStateType.stblock; 900 lcblocklevel = 0; 901 addTokenToStatement(ast); 902 } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) { 903 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 904 gcurrentsqlstatement = new TMssqlBlock(vendor); 905 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 906 addTokenToStatement(ast); 907 gst = EFindSqlStateType.stblock; 908 } else { 909 addTokenToStatement(ast); 910 } 911 } else if ((ast.tokencode == TBaseType.rrw_case)) { 912 case_end_nest++; 913 addTokenToStatement(ast); 914 } else if ((ast.tokencode == TBaseType.rrw_end)) { 915 if (case_end_nest > 0) { 916 case_end_nest--; 917 } 918 addTokenToStatement(ast); 919 } else if ((ast.tokencode == TBaseType.rrw_else)) { 920 addTokenToStatement(ast); 921 if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 922 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 923 ) && (case_end_nest == 0)) 924 gcurrentsqlstatement.dummytag = 1; 925 } else { 926 addTokenToStatement(ast); 927 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlset) { 928 if (ast.tokencode == TBaseType.rrw_on) { 929 gst = EFindSqlStateType.stnormal; 930 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 931 } 932 } 933 } 934 break; 935 } 936 case ststoredprocedure: { 937 if (TBaseType.assigned(lcnextsqlstatement)) { 938 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 939 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 940 gcurrentsqlstatement = lcnextsqlstatement; 941 addTokenToStatement(ast); 942 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 943 gst = EFindSqlStateType.stnormal; 944 } else { 945 gst = EFindSqlStateType.ststoredprocedurebody; 946 addTokenToStatement(ast); 947 948 lcnextsqlstatement = null; 949 } 950 } 951 952 if (gst == EFindSqlStateType.ststoredprocedure) { 953 addTokenToStatement(ast); 954 if (ast.tokencode == TBaseType.rrw_begin) { 955 gst = EFindSqlStateType.stblock; 956 } 957 } 958 break; 959 } 960 case ststoredprocedurebody: { 961 if (TBaseType.assigned(lcnextsqlstatement)) { 962 switch (lcnextsqlstatement.sqlstatementtype) { 963 case sstmssqlgo: { 964 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 965 gcurrentsqlstatement = lcnextsqlstatement; 966 addTokenToStatement(ast); 967 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 968 gst = EFindSqlStateType.stnormal; 969 break; 970 } 971 case sstmssqlcreateprocedure: 972 case sstmssqlcreatefunction: 973 case sstcreatetrigger: 974 case sstmssqlalterprocedure: 975 case sstmssqlalterfunction: 976 case sstmssqlaltertrigger: { 977 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 978 gcurrentsqlstatement = lcnextsqlstatement; 979 addTokenToStatement(ast); 980 gst = EFindSqlStateType.ststoredprocedure; 981 break; 982 } 983 default: { 984 lcnextsqlstatement = null; 985 break; 986 } 987 } 988 } 989 990 if (gst == EFindSqlStateType.ststoredprocedurebody) 991 addTokenToStatement(ast); 992 } 993 break; 994 } 995 } 996 997 // last statement 998 if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) { 999 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder); 1000 } 1001 1002 builder.sqlStatements(this.sqlstatements); 1003 builder.errorCode(errorcount); 1004 builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount)); 1005 } 1006}