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