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