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.ident && ast.tokentype == ETokenType.ttdbstring) { 712 // Handle bracket-quoted XML method names: .[value](), .[nodes](), etc. 713 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 714 TSourceToken st1 = ast.searchToken('(', 1); 715 if (st1 != null) { 716 String text = ast.toString(); 717 if (text.length() > 2) { 718 String inner = text.substring(1, text.length() - 1).toLowerCase(); 719 if (inner.equals("value")) { 720 ast.tokencode = TBaseType.rrw_xml_value; 721 } else if (inner.equals("modify")) { 722 ast.tokencode = TBaseType.rrw_xml_modify; 723 } else if (inner.equals("query")) { 724 ast.tokencode = TBaseType.rrw_xml_query; 725 } else if (inner.equals("exist")) { 726 ast.tokencode = TBaseType.rrw_xml_exist; 727 } else if (inner.equals("nodes")) { 728 ast.tokencode = TBaseType.rrw_xml_nodes; 729 } 730 } 731 } 732 } 733 } else if (ast.tokencode == TBaseType.rrw_check) { 734 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == TBaseType.rrw_with)) { 735 lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with; 736 } 737 } else if (ast.tokencode == TBaseType.rrw_sqlserver_next) { 738 TSourceToken st1 = ast.nextSolidToken(); 739 if ((st1 != null) && (st1.tokencode == '.')) { 740 ast.tokencode = TBaseType.ident; 741 } 742 } else if (ast.tokencode == TBaseType.rrw_fetch) { 743 if ((lcprevsolidtoken != null) && ((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row) || (lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))) { 744 TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open, -1); 745 if (prev2 == null) { 746 ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch; 747 } 748 } 749 } else if ((ast.tokencode == TBaseType.rrw_exec) || (ast.tokencode == TBaseType.rrw_execute)) { 750 // search ;2 after execute 751 // EXECUTE ApxSQL_Test_Triggers_Add;2 @TableName, @AddFlag 752 int searchRange = 4; 753 TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine(); 754 if (endTokenInSameLine != null) { 755 searchRange = endTokenInSameLine.posinlist - ast.posinlist; 756 } 757 TSourceToken st1 = ast.searchToken(';', searchRange); 758 if (st1 != null) { 759 TSourceToken numSt = st1.nextSolidToken(); 760 if ((numSt != null) && (numSt.tokentype == ETokenType.ttnumber)) { 761 st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number; 762 st1.tokentype = ETokenType.ttidentifier; 763 } 764 } 765 } else if (ast.tokencode == TBaseType.rrw_sqlserver_trim) { 766 TSourceToken st1 = ast.nextSolidToken(); 767 if (st1 != null) { 768 if (st1.tokencode == '(') { 769 // keep as trim keyword 770 } else { 771 ast.tokencode = TBaseType.ident; 772 } 773 } 774 } 775 776 if (vendor == EDbVendor.dbvopenedge){ 777 if (ast.tokencode == TBaseType.rrw_order){ 778 TSourceToken st1 = ast.searchToken(TBaseType.rrw_by,1); 779 if (st1 == null) { 780 ast.tokencode = TBaseType.ident; 781 } 782 }else if (ast.tokencode == TBaseType.rrw_with){ 783 TSourceToken st1 = ast.searchToken(TBaseType.rrw_check,1); 784 if (st1 != null) { 785 ast.tokencode = TBaseType.rrw_openedge_with_check; 786 } 787 } 788 } 789 790 if (gst == EFindSqlStateType.ststoredprocedurebody) { 791 if (!((ast.tokencode == TBaseType.rrw_go) 792 || (ast.tokencode == TBaseType.rrw_create) 793 || (ast.tokencode == TBaseType.rrw_alter))) { 794 gcurrentsqlstatement.sourcetokenlist.add(ast); 795 continue; 796 } 797 } 798 799 TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement); 800 801 switch (gst) { 802 case sterror: { 803 if (TBaseType.assigned(lcnextsqlstatement)) { 804 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 805 gcurrentsqlstatement = lcnextsqlstatement; 806 gcurrentsqlstatement.sourcetokenlist.add(ast); 807 gst = EFindSqlStateType.stsql; 808 } else if ((ast.tokentype == ETokenType.ttsemicolon)) { 809 gcurrentsqlstatement.sourcetokenlist.add(ast); 810 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 811 gst = EFindSqlStateType.stnormal; 812 } else { 813 gcurrentsqlstatement.sourcetokenlist.add(ast); 814 } 815 break; 816 } 817 case stnormal: { 818 if ((ast.tokencode == TBaseType.cmtdoublehyphen) 819 || (ast.tokencode == TBaseType.cmtslashstar) 820 || (ast.tokencode == TBaseType.lexspace) 821 || (ast.tokencode == TBaseType.lexnewline) 822 || (ast.tokentype == ETokenType.ttsemicolon)) { 823 if (TBaseType.assigned(gcurrentsqlstatement)) { 824 gcurrentsqlstatement.sourcetokenlist.add(ast); 825 } 826 827 if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) { 828 if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) { 829 // ;;;; continuous semicolon,treat it as comment 830 ast.tokentype = ETokenType.ttsimplecomment; 831 ast.tokencode = TBaseType.cmtdoublehyphen; 832 } 833 } 834 835 continue; 836 } 837 838 gcurrentsqlstatement = lcnextsqlstatement; 839 840 if (TBaseType.assigned(gcurrentsqlstatement)) { 841 switch (gcurrentsqlstatement.sqlstatementtype) { 842 case sstmssqlcreateprocedure: 843 case sstmssqlcreatefunction: 844 case sstcreatetrigger: 845 case sstmssqlalterprocedure: 846 case sstmssqlalterfunction: 847 case sstmssqlaltertrigger: { 848 gcurrentsqlstatement.sourcetokenlist.add(ast); 849 gst = EFindSqlStateType.ststoredprocedure; 850 break; 851 } 852 case sstmssqlbegintry: 853 case sstmssqlbegincatch: { 854 gcurrentsqlstatement.sourcetokenlist.add(ast); 855 gst = EFindSqlStateType.sttrycatch; 856 lctrycatchlevel = 0; 857 break; 858 } 859 case sstmssqlgo: { 860 gcurrentsqlstatement.sourcetokenlist.add(ast); 861 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 862 gst = EFindSqlStateType.stnormal; 863 break; 864 } 865 default: { 866 gcurrentsqlstatement.sourcetokenlist.add(ast); 867 gst = EFindSqlStateType.stsql; 868 break; 869 } 870 } 871 } else { 872 if (ast.tokencode == TBaseType.rrw_begin) { 873 gcurrentsqlstatement = new TMssqlBlock(vendor); 874 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 875 gcurrentsqlstatement.sourcetokenlist.add(ast); 876 gst = EFindSqlStateType.stblock; 877 } else { 878 if (sqlstatements.size() == 0) { 879 //first statement of mssql batch, treat it as exec sp 880 gst = EFindSqlStateType.stsql; 881 gcurrentsqlstatement = new TMssqlExecute(vendor); 882 gcurrentsqlstatement.sourcetokenlist.add(ast); 883 } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) { 884 // prev sql is go, treat it as exec sp 885 gst = EFindSqlStateType.stsql; 886 gcurrentsqlstatement = new TMssqlExecute(vendor); 887 gcurrentsqlstatement.sourcetokenlist.add(ast); 888 } 889 } 890 } 891 892 if (!TBaseType.assigned(gcurrentsqlstatement)) //error tokentext found 893 { 894 this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo) 895 , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist)); 896 897 ast.tokentype = ETokenType.tttokenlizererrortoken; 898 gst = EFindSqlStateType.sterror; 899 900 gcurrentsqlstatement = new TUnknownSqlStatement(vendor); 901 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 902 gcurrentsqlstatement.sourcetokenlist.add(ast); 903 } 904 break; 905 } 906 case stblock: { 907 if (TBaseType.assigned(lcnextsqlstatement)) { 908 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 909 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 910 gcurrentsqlstatement = lcnextsqlstatement; 911 gcurrentsqlstatement.sourcetokenlist.add(ast); 912 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 913 gst = EFindSqlStateType.stnormal; 914 } else { 915 lcnextsqlstatement = null; 916 } 917 } 918 919 if (gst == EFindSqlStateType.stblock) { 920 gcurrentsqlstatement.sourcetokenlist.add(ast); 921 if (ast.tokencode == TBaseType.rrw_begin) { 922 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 923 if (TBaseType.assigned(lcnextsolidtoken)) { 924 if (!((lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_tran) 925 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_transaction) 926 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_distributed) 927 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_dialog) 928 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 929 )) 930 lcblocklevel++; 931 } else 932 lcblocklevel++; 933 934 } else if (ast.tokencode == TBaseType.rrw_case) 935 lcblocklevel++; 936 else if (ast.tokencode == TBaseType.rrw_end) { 937 938 lcisendconversation = false; 939 940 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 941 if (TBaseType.assigned(lcnextsolidtoken)) { 942 if (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 943 lcisendconversation = true; 944 } 945 946 if (!lcisendconversation) { 947 948 if (lcblocklevel == 0) { 949 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 950 if (TBaseType.assigned(lcnextsolidtoken)) { 951 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 952 gst = EFindSqlStateType.stsql; 953 } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) { 954 lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false); 955 if (TBaseType.assigned(lcnnextsolidtoken)) { 956 if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) { 957 gst = EFindSqlStateType.stsql; 958 } 959 } 960 } 961 } 962 } 963 964 if (gst != EFindSqlStateType.stsql) { 965 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 966 gst = EFindSqlStateType.stnormal; 967 } 968 969 } else { 970 lcblocklevel--; 971 } 972 973 } 974 } 975 } 976 break; 977 } 978 case sttrycatch: { 979 980 if (TBaseType.assigned(lcnextsqlstatement)) { 981 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 982 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 983 gcurrentsqlstatement = lcnextsqlstatement; 984 gcurrentsqlstatement.sourcetokenlist.add(ast); 985 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 986 gst = EFindSqlStateType.stnormal; 987 } else { 988 if ( 989 (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry) 990 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 991 ) 992 lctrycatchlevel++; 993 lcnextsqlstatement = null; 994 } 995 } 996 997 if (gst == EFindSqlStateType.sttrycatch) { 998 gcurrentsqlstatement.sourcetokenlist.add(ast); 999 if ((ast.tokencode == TBaseType.rrw_try) || 1000 (ast.tokencode == TBaseType.rrw_catch)) { 1001 if (TBaseType.assigned(lcprevsolidtoken)) { 1002 if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) { 1003 if (lctrycatchlevel == 0) { 1004 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1005 gst = EFindSqlStateType.stnormal; 1006 } else 1007 lctrycatchlevel--; 1008 } 1009 } 1010 } 1011 } 1012 break; 1013 } 1014 case stprocedureWithReturn: { 1015 // found return statement in create procedure/function 1016 1017 if (TBaseType.assigned(lcnextsqlstatement)) { 1018 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 1019 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1020 gcurrentsqlstatement = lcnextsqlstatement; 1021 gcurrentsqlstatement.sourcetokenlist.add(ast); 1022 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1023 gst = EFindSqlStateType.stnormal; 1024 break; 1025 } 1026 } 1027 1028 gcurrentsqlstatement.sourcetokenlist.add(ast); 1029 if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)) { 1030 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1031 gst = EFindSqlStateType.stnormal; 1032 } 1033 break; 1034 } 1035 case stsql: { 1036 if ((ast.tokentype == ETokenType.ttsemicolon)) { 1037 lcstillinsql = false; 1038 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 1039 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 1040 if (TBaseType.assigned(lcnextsolidtoken)) { 1041 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 1042 // if ( expr stmt; else 1043 gcurrentsqlstatement.sourcetokenlist.add(ast); 1044 lcstillinsql = true; 1045 } 1046 1047 } 1048 } 1049 1050 if (!lcstillinsql) { 1051 gst = EFindSqlStateType.stnormal; 1052 gcurrentsqlstatement.sourcetokenlist.add(ast); 1053 gcurrentsqlstatement.semicolonended = ast; 1054 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1055 } 1056 1057 } else if (TBaseType.assigned(lcnextsqlstatement)) { 1058 1059 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 1060 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1061 gcurrentsqlstatement = lcnextsqlstatement; 1062 gcurrentsqlstatement.sourcetokenlist.add(ast); 1063 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1064 gst = EFindSqlStateType.stnormal; 1065 continue; 1066 } 1067 1068 switch (gcurrentsqlstatement.sqlstatementtype) { 1069 case sstmssqlif: 1070 case sstmssqlwhile: { 1071 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 1072 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) { 1073 gcurrentsqlstatement.sourcetokenlist.add(ast); 1074 gst = EFindSqlStateType.stblock; 1075 lcblocklevel = 1; 1076 lcnextsqlstatement = null; 1077 continue; 1078 1079 } else if (gcurrentsqlstatement.dummytag == 1) { 1080 // if ( cond ^stmt nextstmt (^ stands for current pos) 1081 gcurrentsqlstatement.sourcetokenlist.add(ast); 1082 1083 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 1084 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) 1085 gcurrentsqlstatement.dummytag = 1; 1086 else 1087 gcurrentsqlstatement.dummytag = 0; 1088 1089 lcnextsqlstatement = null; 1090 continue; 1091 } else { 1092 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 1093 if ((ast.nextSolidToken() != null) && (ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)) { 1094 gcurrentsqlstatement.sourcetokenlist.add(ast); 1095 lcnextsqlstatement = null; 1096 continue; 1097 } 1098 } 1099 } 1100 break; 1101 } 1102 case sstmssqlalterqueue: { 1103 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) { 1104 // execute can't be used to delimite alter queue 1105 gcurrentsqlstatement.sourcetokenlist.add(ast); 1106 lcnextsqlstatement = null; 1107 continue; 1108 1109 } 1110 break; 1111 } 1112 case sstmssqlcreateschema: { 1113 gcurrentsqlstatement.sourcetokenlist.add(ast); 1114 lcnextsqlstatement = null; 1115 continue; 1116 } 1117 } 1118 1119 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1120 gcurrentsqlstatement = lcnextsqlstatement; 1121 gcurrentsqlstatement.sourcetokenlist.add(ast); 1122 1123 switch (gcurrentsqlstatement.sqlstatementtype) { 1124 case sstmssqlcreateprocedure: 1125 case sstmssqlcreatefunction: 1126 case sstcreatetrigger: 1127 case sstmssqlalterprocedure: 1128 case sstmssqlalterfunction: 1129 case sstmssqlaltertrigger: { 1130 gst = EFindSqlStateType.ststoredprocedure; 1131 break; 1132 } 1133 case sstmssqlbegintry: 1134 case sstmssqlbegincatch: { 1135 gst = EFindSqlStateType.sttrycatch; 1136 lctrycatchlevel = 0; 1137 break; 1138 } 1139 case sstmssqlgo: { 1140 gst = EFindSqlStateType.stnormal; 1141 break; 1142 } 1143 default: { 1144 gst = EFindSqlStateType.stsql; 1145 break; 1146 } 1147 } 1148 1149 } else if ((ast.tokencode == TBaseType.rrw_begin)) { 1150 if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 1151 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) { 1152 gst = EFindSqlStateType.stblock; 1153 lcblocklevel = 0; 1154 gcurrentsqlstatement.sourcetokenlist.add(ast); 1155 } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) { 1156 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1157 gcurrentsqlstatement = new TMssqlBlock(vendor); 1158 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 1159 gcurrentsqlstatement.sourcetokenlist.add(ast); 1160 gst = EFindSqlStateType.stblock; 1161 } else { 1162 gcurrentsqlstatement.sourcetokenlist.add(ast); 1163 } 1164 } else if ((ast.tokencode == TBaseType.rrw_case)) { 1165 case_end_nest++; 1166 gcurrentsqlstatement.sourcetokenlist.add(ast); 1167 } else if ((ast.tokencode == TBaseType.rrw_end)) { 1168 if (case_end_nest > 0) { 1169 case_end_nest--; 1170 } 1171 gcurrentsqlstatement.sourcetokenlist.add(ast); 1172 } else if ((ast.tokencode == TBaseType.rrw_else)) { 1173 gcurrentsqlstatement.sourcetokenlist.add(ast); 1174 if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 1175 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 1176 ) && (case_end_nest == 0)) 1177 gcurrentsqlstatement.dummytag = 1; 1178 } else { 1179 gcurrentsqlstatement.sourcetokenlist.add(ast); 1180 } 1181 break; 1182 } 1183 case ststoredprocedure: { 1184 if (TBaseType.assigned(lcnextsqlstatement)) { 1185 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 1186 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1187 gcurrentsqlstatement = lcnextsqlstatement; 1188 gcurrentsqlstatement.sourcetokenlist.add(ast); 1189 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1190 gst = EFindSqlStateType.stnormal; 1191 } else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn) { 1192 gst = EFindSqlStateType.stprocedureWithReturn; 1193 gcurrentsqlstatement.sourcetokenlist.add(ast); 1194 lcnextsqlstatement = null; 1195 } else { 1196 gst = EFindSqlStateType.ststoredprocedurebody; 1197 gcurrentsqlstatement.sourcetokenlist.add(ast); 1198 1199 lcnextsqlstatement = null; 1200 } 1201 } 1202 1203 if (gst == EFindSqlStateType.ststoredprocedure) { 1204 gcurrentsqlstatement.sourcetokenlist.add(ast); 1205 if (ast.tokencode == TBaseType.rrw_begin) { 1206 gst = EFindSqlStateType.stblock; 1207 } 1208 } 1209 break; 1210 } 1211 case ststoredprocedurebody: { 1212 if (TBaseType.assigned(lcnextsqlstatement)) { 1213 switch (lcnextsqlstatement.sqlstatementtype) { 1214 case sstmssqlgo: { 1215 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1216 gcurrentsqlstatement = lcnextsqlstatement; 1217 gcurrentsqlstatement.sourcetokenlist.add(ast); 1218 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1219 gst = EFindSqlStateType.stnormal; 1220 break; 1221 } 1222 case sstmssqlcreateprocedure: 1223 case sstmssqlcreatefunction: 1224 case sstcreatetrigger: 1225 case sstmssqlalterprocedure: 1226 case sstmssqlalterfunction: 1227 case sstmssqlaltertrigger: { 1228 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1229 gcurrentsqlstatement = lcnextsqlstatement; 1230 gcurrentsqlstatement.sourcetokenlist.add(ast); 1231 gst = EFindSqlStateType.ststoredprocedure; 1232 break; 1233 } 1234 case sstcreateview: 1235 case sstcreatetable: { 1236 1237 boolean readForNewStmt = false; 1238 TSourceToken st1 = ast.searchToken(';', -1); 1239 if (st1 != null) { 1240 TSourceToken st2 = ast.searchToken(TBaseType.rrw_end, -2); 1241 if (st2 != null) { 1242 // Verify this END is at block level 0 (not inside a nested 1243 // BEGIN...END or BEGIN TRY...END TRY block) by counting 1244 // BEGINs and ENDs in the current proc's token list. 1245 int blockDepth = 0; 1246 for (int k = 0; k < gcurrentsqlstatement.sourcetokenlist.size(); k++) { 1247 TSourceToken tk = gcurrentsqlstatement.sourcetokenlist.get(k); 1248 if (tk.tokencode == TBaseType.rrw_begin) { 1249 TSourceToken tkNext = tk.nextSolidToken(); 1250 if (tkNext == null || (tkNext.tokencode != TBaseType.rrw_sqlserver_tran 1251 && tkNext.tokencode != TBaseType.rrw_sqlserver_transaction 1252 && tkNext.tokencode != TBaseType.rrw_sqlserver_distributed 1253 && tkNext.tokencode != TBaseType.rrw_sqlserver_dialog 1254 && tkNext.tokencode != TBaseType.rrw_sqlserver_conversation)) { 1255 blockDepth++; 1256 } 1257 } else if (tk.tokencode == TBaseType.rrw_end) { 1258 TSourceToken tkNext = tk.nextSolidToken(); 1259 if (tkNext == null || tkNext.tokencode != TBaseType.rrw_sqlserver_conversation) { 1260 blockDepth--; 1261 } 1262 } 1263 } 1264 // blockDepth == 0 means all BEGIN/END pairs are balanced 1265 // so the END; is at the top level (proc boundary) 1266 if (blockDepth == 0) { 1267 readForNewStmt = true; 1268 } 1269 } 1270 } 1271 1272 if (readForNewStmt) { 1273 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1274 gcurrentsqlstatement = lcnextsqlstatement; 1275 gcurrentsqlstatement.sourcetokenlist.add(ast); 1276 gst = EFindSqlStateType.stsql; 1277 } else { 1278 lcnextsqlstatement = null; 1279 } 1280 break; 1281 } 1282 case sstmssqlDropSecurityPolicy: 1283 case sstmssqlAlterSecurityPolicy: 1284 case sstmssqlCreateSecurityPolicy: 1285 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1286 gcurrentsqlstatement = lcnextsqlstatement; 1287 gcurrentsqlstatement.sourcetokenlist.add(ast); 1288 gst = EFindSqlStateType.stsql; 1289 1290 break; 1291 default: { 1292 lcnextsqlstatement = null; 1293 break; 1294 } 1295 } 1296 } 1297 1298 if (gst == EFindSqlStateType.ststoredprocedurebody) 1299 gcurrentsqlstatement.sourcetokenlist.add(ast); 1300 } 1301 break; 1302 } 1303 } 1304 1305 //last statement 1306 if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) { 1307 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder); 1308 } 1309 1310 // Set results in builder 1311 builder.sqlStatements(this.sqlstatements); 1312 builder.errorCode(errorcount); 1313 builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount)); 1314 } 1315}