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