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