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.TLexerSoql; 010import gudusoft.gsqlparser.TParserSoql; 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 * Salesforce SOQL (Salesforce Object Query Language) parser implementation. 044 * 045 * <p>This parser handles SOQL-specific SQL syntax including: 046 * <ul> 047 * <li>SOQL SELECT statements</li> 048 * <li>SOQL relationship queries</li> 049 * <li>SOQL aggregate functions</li> 050 * <li>Salesforce-specific syntax elements</li> 051 * </ul> 052 * 053 * <p><b>Design Notes:</b> 054 * <ul> 055 * <li>Extends {@link AbstractSqlParser} using the template method pattern</li> 056 * <li>Uses {@link TLexerSoql} for tokenization</li> 057 * <li>Uses {@link TParserSoql} for parsing</li> 058 * <li>Tokenization follows MSSQL pattern</li> 059 * <li>Delimiter character: ';' for SOQL statements</li> 060 * </ul> 061 * 062 * @see SqlParser 063 * @see AbstractSqlParser 064 * @see TLexerSoql 065 * @see TParserSoql 066 * @since 3.2.0.0 067 */ 068public class SoqlSqlParser extends AbstractSqlParser { 069 070 /** 071 * Construct SOQL parser. 072 * <p> 073 * Configures the parser for Salesforce SOQL with default delimiter (;). 074 */ 075 public SoqlSqlParser() { 076 super(EDbVendor.dbvsoql); 077 this.delimiterChar = ';'; 078 this.defaultDelimiterStr = ";"; 079 080 // Create lexer once - will be reused for all parsing operations 081 this.flexer = new TLexerSoql(); 082 this.flexer.delimiterchar = this.delimiterChar; 083 this.flexer.defaultDelimiterStr = this.defaultDelimiterStr; 084 085 // Set parent's lexer reference for shared tokenization logic 086 this.lexer = this.flexer; 087 088 // Create parser once - will be reused for all parsing operations 089 this.fparser = new TParserSoql(null); 090 this.fparser.lexer = this.flexer; 091 } 092 093 // ========== Parser Components ========== 094 095 /** The SOQL lexer used for tokenization */ 096 public TLexerSoql flexer; 097 098 /** SOQL parser (for SOQL statements) */ 099 private TParserSoql fparser; 100 101 /** Current statement being built during extraction */ 102 private TCustomSqlStatement gcurrentsqlstatement; 103 104 // ========== AbstractSqlParser Abstract Methods Implementation ========== 105 106 /** 107 * Return the SOQL lexer instance. 108 */ 109 @Override 110 protected TCustomLexer getLexer(ParserContext context) { 111 return this.flexer; 112 } 113 114 /** 115 * Return the SOQL parser instance with updated token list. 116 */ 117 @Override 118 protected TCustomParser getParser(ParserContext context, TSourceTokenList tokens) { 119 this.fparser.sourcetokenlist = tokens; 120 return this.fparser; 121 } 122 123 /** 124 * Call SOQL-specific tokenization logic. 125 * <p> 126 * SOQL uses MSSQL-like tokenization. 127 */ 128 @Override 129 protected void tokenizeVendorSql() { 130 dosoqlsqltexttotokenlist(); 131 } 132 133 /** 134 * Setup SOQL parser for raw statement extraction. 135 */ 136 @Override 137 protected void setupVendorParsersForExtraction() { 138 this.fparser.sqlcmds = this.sqlcmds; 139 this.fparser.sourcetokenlist = this.sourcetokenlist; 140 } 141 142 /** 143 * Call SOQL-specific raw statement extraction logic. 144 */ 145 @Override 146 protected void extractVendorRawStatements(SqlParseResult.Builder builder) { 147 dosoqlgetrawsqlstatements(builder); 148 } 149 150 /** 151 * Perform full parsing of statements with syntax checking. 152 */ 153 @Override 154 protected TStatementList performParsing(ParserContext context, 155 TCustomParser parser, 156 TCustomParser secondaryParser, 157 TSourceTokenList tokens, 158 TStatementList rawStatements) { 159 this.fparser = (TParserSoql) parser; 160 this.sourcetokenlist = tokens; 161 this.parserContext = context; 162 this.sqlstatements = rawStatements; 163 164 this.sqlcmds = SqlCmdsFactory.get(vendor); 165 this.fparser.sqlcmds = this.sqlcmds; 166 167 if (context != null && context.getGsqlparser() != null) { 168 TGSqlParser gsqlparser = (TGSqlParser) context.getGsqlparser(); 169 this.frameStack = gsqlparser.getFrameStack(); 170 this.fparser.getNf().setGsqlParser(gsqlparser); 171 this.globalContext = new TContext(); 172 this.sqlEnv = new TSQLEnv(this.vendor) { 173 @Override 174 public void initSQLEnv() { 175 } 176 }; 177 this.globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements); 178 } else { 179 initializeGlobalContext(); 180 } 181 182 for (int i = 0; i < sqlstatements.size(); i++) { 183 TCustomSqlStatement stmt = sqlstatements.getRawSql(i); 184 185 try { 186 stmt.setFrameStack(frameStack); 187 int parseResult = stmt.parsestatement(null, false, context.isOnlyNeedRawParseTree()); 188 189 boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE; 190 if (doRecover && ((parseResult != 0) || (stmt.getErrorCount() > 0))) { 191 handleCreateTableErrorRecovery(stmt); 192 } 193 194 if ((parseResult != 0) || (stmt.getErrorCount() > 0)) { 195 copyErrorsFromStatement(stmt); 196 } 197 198 } catch (Exception ex) { 199 handleStatementParsingException(stmt, i, ex); 200 continue; 201 } 202 } 203 204 if (globalFrame != null) { 205 globalFrame.popMeFromStack(frameStack); 206 } 207 208 return this.sqlstatements; 209 } 210 211 private void handleCreateTableErrorRecovery(TCustomSqlStatement stmt) { 212 if (((stmt.sqlstatementtype == ESqlStatementType.sstcreatetable) 213 || (stmt.sqlstatementtype == ESqlStatementType.sstcreateindex)) 214 && (!TBaseType.c_createTableStrictParsing)) { 215 216 int nested = 0; 217 boolean isIgnore = false, isFoundIgnoreToken = false; 218 TSourceToken firstIgnoreToken = null; 219 220 for (int k = 0; k < stmt.sourcetokenlist.size(); k++) { 221 TSourceToken st = stmt.sourcetokenlist.get(k); 222 if (isIgnore) { 223 if (st.issolidtoken() && (st.tokencode != ';')) { 224 isFoundIgnoreToken = true; 225 if (firstIgnoreToken == null) { 226 firstIgnoreToken = st; 227 } 228 } 229 if (st.tokencode != ';') { 230 st.tokencode = TBaseType.sqlpluscmd; 231 } 232 continue; 233 } 234 if (st.tokencode == (int) ')') { 235 nested--; 236 if (nested == 0) { 237 boolean isSelect = false; 238 TSourceToken st1 = st.searchToken(TBaseType.rrw_as, 1); 239 if (st1 != null) { 240 TSourceToken st2 = st.searchToken((int) '(', 2); 241 if (st2 != null) { 242 TSourceToken st3 = st.searchToken(TBaseType.rrw_select, 3); 243 isSelect = (st3 != null); 244 } 245 } 246 if (!isSelect) isIgnore = true; 247 } 248 } else if (st.tokencode == (int) '(') { 249 nested++; 250 } 251 } 252 253 if (isFoundIgnoreToken) { 254 stmt.clearError(); 255 stmt.parsestatement(null, false); 256 } 257 } 258 } 259 260 @Override 261 protected void performSemanticAnalysis(ParserContext context, TStatementList statements) { 262 if (context != null && context.getGsqlparser() != null) { 263 return; 264 } 265 266 if (getSyntaxErrors().isEmpty()) { 267 if (TBaseType.isEnableResolver2()) { 268 TSQLResolverConfig config = new TSQLResolverConfig(); 269 config.setVendor(vendor); 270 TSQLResolver2 resolver2 = new TSQLResolver2(null, statements, config); 271 if (this.sqlEnv != null) { 272 resolver2.setSqlEnv(this.sqlEnv); 273 } 274 resolver2.resolve(); 275 } else if (TBaseType.isEnableResolver()) { 276 TSQLResolver resolver = new TSQLResolver(globalContext, statements); 277 resolver.resolve(); 278 } 279 } 280 } 281 282 @Override 283 protected void performInterpreter(ParserContext context, TStatementList statements) { 284 if (TBaseType.ENABLE_INTERPRETER && getSyntaxErrors().isEmpty()) { 285 TLog.clearLogs(); 286 TGlobalScope interpreterScope = new TGlobalScope(sqlEnv); 287 TLog.enableInterpreterLogOnly(); 288 TASTEvaluator astEvaluator = new TASTEvaluator(statements, interpreterScope); 289 astEvaluator.eval(); 290 } 291 } 292 293 // ========== Helper Methods ========== 294 295 /** 296 * Add token to current statement with proper statement linkage. 297 * This replicates TCustomSqlStatement.addtokentolist() behavior 298 * which sets st.stmt = this before adding. 299 */ 300 private void addTokenToStatement(TSourceToken st) { 301 st.stmt = gcurrentsqlstatement; 302 gcurrentsqlstatement.sourcetokenlist.add(st); 303 } 304 305 // ========== SOQL-Specific Tokenization ========== 306 307 /** 308 * SOQL-specific tokenization logic. 309 * <p> 310 * SOQL uses MSSQL-like tokenization. 311 * Migrated from TGSqlParser.dosoqlsqltexttotokenlist() 312 */ 313 private void dosoqlsqltexttotokenlist() { 314 // SOQL tokenization follows MSSQL pattern 315 TSourceToken lcprevtoken = null; 316 int lcsteps = 0; 317 TSourceToken asourcetoken, lctoken, lctoken2, lctoken3; 318 int yychar; 319 boolean iskeywordgo; 320 321 asourcetoken = getanewsourcetoken(); 322 323 if (asourcetoken == null) return; 324 325 yychar = asourcetoken.tokencode; 326 327 boolean lcinopenrowset = false; 328 int lcnested = 0; 329 330 while (yychar > 0) { 331 332 if (asourcetoken.tokencode == TBaseType.rrw_openrowset) { 333 lcinopenrowset = true; 334 lcnested = 0; 335 } else if (asourcetoken.tokentype == ETokenType.ttleftparenthesis) { 336 if ((lcsteps > 0) && TBaseType.assigned(lcprevtoken)) { 337 if (lcprevtoken.tokencode == TBaseType.rrw_primary) { 338 lcprevtoken.tokencode = TBaseType.rrw_select - 2; 339 checkconstarinttoken(lcprevtoken); 340 } else if (lcprevtoken.tokencode == TBaseType.rrw_foreign) { 341 lcprevtoken.tokencode = TBaseType.rrw_select - 4; 342 checkconstarinttoken(lcprevtoken); 343 } else if (lcprevtoken.tokencode == TBaseType.rrw_unique) { 344 lcprevtoken.tokencode = TBaseType.rrw_select - 1; 345 checkconstarinttoken(lcprevtoken); 346 } 347 lcprevtoken = null; 348 lcsteps = 0; 349 } 350 351 if (lcinopenrowset) 352 lcnested++; 353 } else if (asourcetoken.tokentype == ETokenType.ttrightparenthesis) { 354 if (lcinopenrowset) { 355 if ((lcnested > 0)) 356 lcnested--; 357 if (lcnested == 0) 358 lcinopenrowset = false; 359 } 360 } else if (asourcetoken.tokentype == ETokenType.ttsemicolon) { 361 if (lcinopenrowset) { 362 asourcetoken.tokentype = ETokenType.ttsemicolon2; 363 } else { 364 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin, -1); 365 if (lctoken2 != null) { 366 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 367 asourcetoken.tokentype = ETokenType.ttsemicolon3; 368 } else { 369 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try, -1); 370 if (lctoken2 == null) { 371 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch, -1); 372 } 373 if (lctoken2 != null) { 374 lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin, -2); 375 if (lctoken3 != null) { 376 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 377 asourcetoken.tokentype = ETokenType.ttsemicolon3; 378 } 379 } 380 } 381 } 382 383 lctoken = getprevtoken(asourcetoken); 384 if ((lctoken != null)) { 385 if (lctoken.tokentype == ETokenType.ttsemicolon) { 386 asourcetoken.tokencode = TBaseType.lexspace; 387 } 388 } 389 } else if (asourcetoken.tokentype == ETokenType.ttperiod) { 390 lctoken = getprevtoken(asourcetoken); 391 if (TBaseType.assigned(lctoken)) { 392 if (lctoken.tokencode == TBaseType.rrw_go) { 393 lctoken.tokencode = TBaseType.ident; 394 lctoken.tokentype = ETokenType.ttidentifier; 395 } 396 } 397 } else if (asourcetoken.tokencode == TBaseType.rrw_table) { 398 lctoken = getprevtoken(asourcetoken); 399 if (TBaseType.assigned(lctoken)) { 400 if (lctoken.tokencode == TBaseType.rrw_lock) { 401 lctoken.tokencode = TBaseType.rw_locktable; 402 } 403 } 404 } else if (asourcetoken.tokencode == TBaseType.rrw_into) { 405 lctoken = getprevtoken(asourcetoken); 406 if (TBaseType.assigned(lctoken)) { 407 if (lctoken.tokencode == TBaseType.rrw_sqlserver_copy) { 408 lctoken.tokencode = TBaseType.rrw_sqlserver_copyinto; 409 } 410 } 411 } else if (asourcetoken.tokencode == TBaseType.rrw_sqlserver_column) { 412 lctoken = getprevtoken(asourcetoken); 413 if (TBaseType.assigned(lctoken)) { 414 if (lctoken.tokencode == TBaseType.rrw_drop) { 415 asourcetoken.tokencode = TBaseType.rrw_sqlserver_drop_column; 416 } 417 } 418 } else if (asourcetoken.tokencode == TBaseType.rrw_go) { 419 iskeywordgo = true; 420 lctoken = getprevtoken(asourcetoken); 421 if (TBaseType.assigned(lctoken)) { 422 if ((lctoken.lineNo == asourcetoken.lineNo) && (lctoken.tokencode != ';')) { 423 iskeywordgo = false; 424 } 425 } 426 427 if (iskeywordgo) { 428 lcinopenrowset = false; 429 lcnested = 0; 430 lcprevtoken = asourcetoken; 431 } else { 432 asourcetoken.tokencode = TBaseType.ident; 433 asourcetoken.tokentype = ETokenType.ttidentifier; 434 } 435 } else if (asourcetoken.tokencode == TBaseType.rrw_primary) { 436 lcsteps = 2; 437 lcprevtoken = asourcetoken; 438 } else if (asourcetoken.tokencode == TBaseType.rrw_foreign) { 439 lcsteps = 2; 440 lcprevtoken = asourcetoken; 441 } else if (asourcetoken.tokencode == TBaseType.rrw_unique) { 442 lcsteps = 1; 443 lcprevtoken = asourcetoken; 444 } else if (asourcetoken.issolidtoken()) { 445 if (lcsteps > 0) { 446 if (!(TBaseType.mysametext("clustered", asourcetoken.toString()) 447 || TBaseType.mysametext("nonclustered", asourcetoken.toString()) 448 || TBaseType.mysametext("hash", asourcetoken.toString()) 449 )) 450 lcsteps--; 451 } 452 } 453 454 sourcetokenlist.add(asourcetoken); 455 456 asourcetoken = getanewsourcetoken(); 457 if (asourcetoken == null) break; 458 yychar = asourcetoken.tokencode; 459 } 460 } 461 462 private TSourceToken getprevtoken(TSourceToken ptoken) { 463 TSourceTokenList lcstlist = ptoken.container; 464 if (TBaseType.assigned(lcstlist)) { 465 if ((ptoken.posinlist > 0) && (lcstlist.size() > ptoken.posinlist - 1)) { 466 if (!((lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttwhitespace) 467 || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttreturn) 468 || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttsimplecomment) 469 || (lcstlist.get(ptoken.posinlist - 1).tokentype == ETokenType.ttbracketedcomment) 470 )) { 471 return lcstlist.get(ptoken.posinlist - 1); 472 } else { 473 return lcstlist.nextsolidtoken(ptoken.posinlist - 1, -1, false); 474 } 475 } 476 } 477 return null; 478 } 479 480 private void checkconstarinttoken(TSourceToken token) { 481 TSourceTokenList lcStList = token.container; 482 if (TBaseType.assigned(lcStList)) { 483 TSourceToken lcPPToken = lcStList.nextsolidtoken(token.posinlist, -2, false); 484 if (TBaseType.assigned(lcPPToken)) { 485 if (lcPPToken.tokencode == flexer.getkeywordvalue("constraint")) { 486 lcPPToken.tokencode = TBaseType.rw_constraint2; 487 } 488 } 489 } 490 } 491 492 // ========== SOQL-Specific Raw Statement Extraction ========== 493 494 /** 495 * SOQL-specific raw statement extraction logic. 496 * <p> 497 * Migrated from TGSqlParser.dosoqlgetrawsqlstatements() 498 */ 499 private void dosoqlgetrawsqlstatements(SqlParseResult.Builder builder) { 500 int errorcount = 0; 501 int case_end_nest = 0; 502 503 if (TBaseType.assigned(sqlstatements)) sqlstatements.clear(); 504 if (!TBaseType.assigned(sourcetokenlist)) { 505 builder.errorCode(-1); 506 builder.errorMessage("Source token list is null"); 507 return; 508 } 509 510 gcurrentsqlstatement = null; 511 EFindSqlStateType gst = EFindSqlStateType.stnormal; 512 int lcblocklevel = 0; 513 int lctrycatchlevel = 0; 514 TSourceToken lcprevsolidtoken = null, lcnextsolidtoken, lcnnextsolidtoken; 515 TSourceToken ast = null; 516 int i, lcMergeInSelectNested = 0; 517 boolean lcisendconversation, lcstillinsql, lcMergeInSelect = false; 518 519 for (i = 0; i < sourcetokenlist.size(); i++) { 520 521 if ((ast != null) && (ast.issolidtoken())) 522 lcprevsolidtoken = ast; 523 524 ast = sourcetokenlist.get(i); 525 sourcetokenlist.curpos = i; 526 527 if (lcMergeInSelect) { 528 if (ast.tokencode == '(') lcMergeInSelectNested++; 529 if (ast.tokencode == ')') { 530 lcMergeInSelectNested--; 531 if (lcMergeInSelectNested == 0) { 532 lcMergeInSelect = false; 533 } 534 } 535 addTokenToStatement(ast); 536 continue; 537 } 538 539 if (ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement) { 540 addTokenToStatement(ast); 541 continue; 542 } 543 544 // SOQL-specific: Handle UPDATE TRACKING/VIEWSTAT clauses 545 // These are SOQL clauses for Knowledge articles, not UPDATE statements 546 if (ast.tokencode == TBaseType.rrw_update) { 547 TSourceToken st1 = ast.nextSolidToken(); 548 if (st1 != null) { 549 if (st1.toString().equalsIgnoreCase("tracking") 550 || st1.toString().equalsIgnoreCase("viewstat")) { 551 // UPDATE TRACKING | UPDATE VIEWSTAT 552 ast.tokencode = TBaseType.rrw_soql_update_tracking; 553 } 554 } 555 } 556 557 if (ast.tokencode == TBaseType.rrw_minus) { 558 TSourceToken st1 = ast.searchToken('(', 1); 559 if (st1 == null) { 560 st1 = ast.searchToken(TBaseType.rrw_select, 1); 561 if (st1 == null) { 562 ast.tokencode = TBaseType.ident; 563 } 564 } 565 } else if (ast.tokencode == TBaseType.rrw_merge) { 566 TSourceToken st1 = ast.nextSolidToken(); 567 if (st1 != null && st1.tokencode == TBaseType.rrw_join) { 568 ast.tokencode = TBaseType.rrw_merge2_sqlserver; 569 } 570 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '(')) { 571 lcMergeInSelect = true; 572 lcMergeInSelectNested++; 573 addTokenToStatement(ast); 574 continue; 575 } 576 } else if (ast.tokencode == TBaseType.rrw_sqlserver_value) { 577 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 578 TSourceToken st1 = ast.searchToken('(', 1); 579 if (st1 != null) { 580 ast.tokencode = TBaseType.rrw_xml_value; 581 } 582 } 583 } else if (ast.tokencode == TBaseType.rrw_sqlserver_modify) { 584 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 585 TSourceToken st1 = ast.searchToken('(', 1); 586 if (st1 != null) { 587 ast.tokencode = TBaseType.rrw_xml_modify; 588 } 589 } 590 } else if (ast.tokencode == TBaseType.rrw_sqlserver_query) { 591 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 592 TSourceToken st1 = ast.searchToken('(', 1); 593 if (st1 != null) { 594 ast.tokencode = TBaseType.rrw_xml_query; 595 } 596 } 597 } else if (ast.tokencode == TBaseType.rrw_sqlserver_exist) { 598 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 599 TSourceToken st1 = ast.searchToken('(', 1); 600 if (st1 != null) { 601 ast.tokencode = TBaseType.rrw_xml_exist; 602 } 603 } 604 } else if (ast.tokencode == TBaseType.rrw_sqlserver_nodes) { 605 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == '.')) { 606 TSourceToken st1 = ast.searchToken('(', 1); 607 if (st1 != null) { 608 ast.tokencode = TBaseType.rrw_xml_nodes; 609 } 610 } 611 } else if (ast.tokencode == TBaseType.rrw_check) { 612 if ((lcprevsolidtoken != null) && (lcprevsolidtoken.tokencode == TBaseType.rrw_with)) { 613 lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with; 614 } 615 } else if (ast.tokencode == TBaseType.rrw_sqlserver_next) { 616 TSourceToken st1 = ast.nextSolidToken(); 617 if ((st1 != null) && (st1.tokencode == '.')) { 618 ast.tokencode = TBaseType.ident; 619 } 620 } else if (ast.tokencode == TBaseType.rrw_fetch) { 621 if ((lcprevsolidtoken != null) && ((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row) || (lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))) { 622 TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open, -1); 623 if (prev2 == null) { 624 ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch; 625 } 626 } 627 } else if ((ast.tokencode == TBaseType.rrw_exec) || (ast.tokencode == TBaseType.rrw_execute)) { 628 int searchRange = 4; 629 TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine(); 630 if (endTokenInSameLine != null) { 631 searchRange = endTokenInSameLine.posinlist - ast.posinlist; 632 } 633 TSourceToken st1 = ast.searchToken(';', searchRange); 634 if (st1 != null) { 635 TSourceToken numSt = st1.nextSolidToken(); 636 if ((numSt != null) && (numSt.tokentype == ETokenType.ttnumber)) { 637 st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number; 638 st1.tokentype = ETokenType.ttidentifier; 639 } 640 } 641 } else if (ast.tokencode == TBaseType.rrw_sqlserver_trim) { 642 TSourceToken st1 = ast.nextSolidToken(); 643 if (st1 != null) { 644 if (st1.tokencode == '(') { 645 // keep as trim keyword 646 } else { 647 ast.tokencode = TBaseType.ident; 648 } 649 } 650 } 651 652 if (gst == EFindSqlStateType.ststoredprocedurebody) { 653 if (!((ast.tokencode == TBaseType.rrw_go) 654 || (ast.tokencode == TBaseType.rrw_create) 655 || (ast.tokencode == TBaseType.rrw_alter))) { 656 addTokenToStatement(ast); 657 continue; 658 } 659 } 660 661 TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement); 662 663 switch (gst) { 664 case sterror: { 665 if (TBaseType.assigned(lcnextsqlstatement)) { 666 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 667 gcurrentsqlstatement = lcnextsqlstatement; 668 addTokenToStatement(ast); 669 gst = EFindSqlStateType.stsql; 670 } else if ((ast.tokentype == ETokenType.ttsemicolon)) { 671 addTokenToStatement(ast); 672 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 673 gst = EFindSqlStateType.stnormal; 674 } else { 675 addTokenToStatement(ast); 676 } 677 break; 678 } 679 case stnormal: { 680 if ((ast.tokencode == TBaseType.cmtdoublehyphen) 681 || (ast.tokencode == TBaseType.cmtslashstar) 682 || (ast.tokencode == TBaseType.lexspace) 683 || (ast.tokencode == TBaseType.lexnewline) 684 || (ast.tokentype == ETokenType.ttsemicolon)) { 685 if (TBaseType.assigned(gcurrentsqlstatement)) { 686 addTokenToStatement(ast); 687 } 688 689 if (TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon)) { 690 if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon) { 691 ast.tokentype = ETokenType.ttsimplecomment; 692 ast.tokencode = TBaseType.cmtdoublehyphen; 693 } 694 } 695 696 continue; 697 } 698 699 gcurrentsqlstatement = lcnextsqlstatement; 700 701 if (TBaseType.assigned(gcurrentsqlstatement)) { 702 switch (gcurrentsqlstatement.sqlstatementtype) { 703 case sstmssqlcreateprocedure: 704 case sstmssqlcreatefunction: 705 case sstcreatetrigger: 706 case sstmssqlalterprocedure: 707 case sstmssqlalterfunction: 708 case sstmssqlaltertrigger: { 709 addTokenToStatement(ast); 710 gst = EFindSqlStateType.ststoredprocedure; 711 break; 712 } 713 case sstmssqlbegintry: 714 case sstmssqlbegincatch: { 715 addTokenToStatement(ast); 716 gst = EFindSqlStateType.sttrycatch; 717 lctrycatchlevel = 0; 718 break; 719 } 720 case sstmssqlgo: { 721 addTokenToStatement(ast); 722 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 723 gst = EFindSqlStateType.stnormal; 724 break; 725 } 726 default: { 727 addTokenToStatement(ast); 728 gst = EFindSqlStateType.stsql; 729 break; 730 } 731 } 732 } else { 733 if (ast.tokencode == TBaseType.rrw_begin) { 734 gcurrentsqlstatement = new TMssqlBlock(vendor); 735 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 736 addTokenToStatement(ast); 737 gst = EFindSqlStateType.stblock; 738 } else { 739 if (sqlstatements.size() == 0) { 740 gst = EFindSqlStateType.stsql; 741 gcurrentsqlstatement = new TMssqlExecute(vendor); 742 addTokenToStatement(ast); 743 } else if (sqlstatements.get(sqlstatements.size() - 1).sqlstatementtype == ESqlStatementType.sstmssqlgo) { 744 gst = EFindSqlStateType.stsql; 745 gcurrentsqlstatement = new TMssqlExecute(vendor); 746 addTokenToStatement(ast); 747 } 748 } 749 } 750 751 if (!TBaseType.assigned(gcurrentsqlstatement)) { 752 this.syntaxErrors.add(new TSyntaxError(ast.getAstext(), ast.lineNo, (ast.columnNo < 0 ? 0 : ast.columnNo) 753 , "Error when tokenlize", EErrorType.spwarning, TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE, null, ast.posinlist)); 754 755 ast.tokentype = ETokenType.tttokenlizererrortoken; 756 gst = EFindSqlStateType.sterror; 757 758 gcurrentsqlstatement = new TUnknownSqlStatement(vendor); 759 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 760 addTokenToStatement(ast); 761 } 762 break; 763 } 764 case stblock: { 765 if (TBaseType.assigned(lcnextsqlstatement)) { 766 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 767 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 768 gcurrentsqlstatement = lcnextsqlstatement; 769 addTokenToStatement(ast); 770 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 771 gst = EFindSqlStateType.stnormal; 772 } else { 773 lcnextsqlstatement = null; 774 } 775 } 776 777 if (gst == EFindSqlStateType.stblock) { 778 addTokenToStatement(ast); 779 if (ast.tokencode == TBaseType.rrw_begin) { 780 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 781 if (TBaseType.assigned(lcnextsolidtoken)) { 782 if (!((lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_tran) 783 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_transaction) 784 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_distributed) 785 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_dialog) 786 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 787 )) 788 lcblocklevel++; 789 } else 790 lcblocklevel++; 791 792 } else if (ast.tokencode == TBaseType.rrw_case) 793 lcblocklevel++; 794 else if (ast.tokencode == TBaseType.rrw_end) { 795 796 lcisendconversation = false; 797 798 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 799 if (TBaseType.assigned(lcnextsolidtoken)) { 800 if (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 801 lcisendconversation = true; 802 } 803 804 if (!lcisendconversation) { 805 806 if (lcblocklevel == 0) { 807 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 808 if (TBaseType.assigned(lcnextsolidtoken)) { 809 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 810 gst = EFindSqlStateType.stsql; 811 } else if (lcnextsolidtoken.tokentype == ETokenType.ttsemicolon) { 812 lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist, 1, false); 813 if (TBaseType.assigned(lcnnextsolidtoken)) { 814 if (lcnnextsolidtoken.tokencode == TBaseType.rrw_else) { 815 gst = EFindSqlStateType.stsql; 816 } 817 } 818 } 819 } 820 } 821 822 if (gst != EFindSqlStateType.stsql) { 823 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 824 gst = EFindSqlStateType.stnormal; 825 } 826 827 } else { 828 lcblocklevel--; 829 } 830 831 } 832 } 833 } 834 break; 835 } 836 case sttrycatch: { 837 838 if (TBaseType.assigned(lcnextsqlstatement)) { 839 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 840 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 841 gcurrentsqlstatement = lcnextsqlstatement; 842 addTokenToStatement(ast); 843 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 844 gst = EFindSqlStateType.stnormal; 845 } else { 846 if ( 847 (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry) 848 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 849 ) 850 lctrycatchlevel++; 851 lcnextsqlstatement = null; 852 } 853 } 854 855 if (gst == EFindSqlStateType.sttrycatch) { 856 addTokenToStatement(ast); 857 if ((ast.tokencode == TBaseType.rrw_try) || 858 (ast.tokencode == TBaseType.rrw_catch)) { 859 if (TBaseType.assigned(lcprevsolidtoken)) { 860 if (lcprevsolidtoken.tokencode == TBaseType.rrw_end) { 861 if (lctrycatchlevel == 0) { 862 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 863 gst = EFindSqlStateType.stnormal; 864 } else 865 lctrycatchlevel--; 866 } 867 } 868 } 869 } 870 break; 871 } 872 case stprocedureWithReturn: { 873 if (TBaseType.assigned(lcnextsqlstatement)) { 874 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 875 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 876 gcurrentsqlstatement = lcnextsqlstatement; 877 addTokenToStatement(ast); 878 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 879 gst = EFindSqlStateType.stnormal; 880 break; 881 } 882 } 883 884 addTokenToStatement(ast); 885 if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)) { 886 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 887 gst = EFindSqlStateType.stnormal; 888 } 889 break; 890 } 891 case stsql: { 892 if ((ast.tokentype == ETokenType.ttsemicolon)) { 893 lcstillinsql = false; 894 if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 895 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i, 1, false); 896 if (TBaseType.assigned(lcnextsolidtoken)) { 897 if (lcnextsolidtoken.tokencode == TBaseType.rrw_else) { 898 addTokenToStatement(ast); 899 lcstillinsql = true; 900 } 901 902 } 903 } 904 905 if (!lcstillinsql) { 906 gst = EFindSqlStateType.stnormal; 907 addTokenToStatement(ast); 908 gcurrentsqlstatement.semicolonended = ast; 909 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 910 } 911 912 } else if (TBaseType.assigned(lcnextsqlstatement)) { 913 914 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 915 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 916 gcurrentsqlstatement = lcnextsqlstatement; 917 addTokenToStatement(ast); 918 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 919 gst = EFindSqlStateType.stnormal; 920 continue; 921 } 922 923 switch (gcurrentsqlstatement.sqlstatementtype) { 924 case sstmssqlif: 925 case sstmssqlwhile: { 926 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 927 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) { 928 addTokenToStatement(ast); 929 gst = EFindSqlStateType.stblock; 930 lcblocklevel = 1; 931 lcnextsqlstatement = null; 932 continue; 933 934 } else if (gcurrentsqlstatement.dummytag == 1) { 935 addTokenToStatement(ast); 936 937 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 938 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) 939 gcurrentsqlstatement.dummytag = 1; 940 else 941 gcurrentsqlstatement.dummytag = 0; 942 943 lcnextsqlstatement = null; 944 continue; 945 } else { 946 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) { 947 if ((ast.nextSolidToken() != null) && (ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)) { 948 addTokenToStatement(ast); 949 lcnextsqlstatement = null; 950 continue; 951 } 952 } 953 } 954 break; 955 } 956 case sstmssqlalterqueue: { 957 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec) { 958 addTokenToStatement(ast); 959 lcnextsqlstatement = null; 960 continue; 961 962 } 963 break; 964 } 965 case sstmssqlcreateschema: { 966 addTokenToStatement(ast); 967 lcnextsqlstatement = null; 968 continue; 969 } 970 } 971 972 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 973 gcurrentsqlstatement = lcnextsqlstatement; 974 addTokenToStatement(ast); 975 976 switch (gcurrentsqlstatement.sqlstatementtype) { 977 case sstmssqlcreateprocedure: 978 case sstmssqlcreatefunction: 979 case sstcreatetrigger: 980 case sstmssqlalterprocedure: 981 case sstmssqlalterfunction: 982 case sstmssqlaltertrigger: { 983 gst = EFindSqlStateType.ststoredprocedure; 984 break; 985 } 986 case sstmssqlbegintry: 987 case sstmssqlbegincatch: { 988 gst = EFindSqlStateType.sttrycatch; 989 lctrycatchlevel = 0; 990 break; 991 } 992 case sstmssqlgo: { 993 gst = EFindSqlStateType.stnormal; 994 break; 995 } 996 default: { 997 gst = EFindSqlStateType.stsql; 998 break; 999 } 1000 } 1001 1002 } else if ((ast.tokencode == TBaseType.rrw_begin)) { 1003 if ((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 1004 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile)) { 1005 gst = EFindSqlStateType.stblock; 1006 lcblocklevel = 0; 1007 addTokenToStatement(ast); 1008 } else if (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare) { 1009 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1010 gcurrentsqlstatement = new TMssqlBlock(vendor); 1011 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 1012 addTokenToStatement(ast); 1013 gst = EFindSqlStateType.stblock; 1014 } else { 1015 addTokenToStatement(ast); 1016 } 1017 } else if ((ast.tokencode == TBaseType.rrw_case)) { 1018 case_end_nest++; 1019 addTokenToStatement(ast); 1020 } else if ((ast.tokencode == TBaseType.rrw_end)) { 1021 if (case_end_nest > 0) { 1022 case_end_nest--; 1023 } 1024 addTokenToStatement(ast); 1025 } else if ((ast.tokencode == TBaseType.rrw_else)) { 1026 addTokenToStatement(ast); 1027 if (((gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 1028 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 1029 ) && (case_end_nest == 0)) 1030 gcurrentsqlstatement.dummytag = 1; 1031 } else { 1032 addTokenToStatement(ast); 1033 } 1034 break; 1035 } 1036 case ststoredprocedure: { 1037 if (TBaseType.assigned(lcnextsqlstatement)) { 1038 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 1039 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1040 gcurrentsqlstatement = lcnextsqlstatement; 1041 addTokenToStatement(ast); 1042 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1043 gst = EFindSqlStateType.stnormal; 1044 } else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn) { 1045 gst = EFindSqlStateType.stprocedureWithReturn; 1046 addTokenToStatement(ast); 1047 lcnextsqlstatement = null; 1048 } else { 1049 gst = EFindSqlStateType.ststoredprocedurebody; 1050 addTokenToStatement(ast); 1051 1052 lcnextsqlstatement = null; 1053 } 1054 } 1055 1056 if (gst == EFindSqlStateType.ststoredprocedure) { 1057 addTokenToStatement(ast); 1058 if (ast.tokencode == TBaseType.rrw_begin) { 1059 gst = EFindSqlStateType.stblock; 1060 } 1061 } 1062 break; 1063 } 1064 case ststoredprocedurebody: { 1065 if (TBaseType.assigned(lcnextsqlstatement)) { 1066 switch (lcnextsqlstatement.sqlstatementtype) { 1067 case sstmssqlgo: { 1068 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1069 gcurrentsqlstatement = lcnextsqlstatement; 1070 addTokenToStatement(ast); 1071 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1072 gst = EFindSqlStateType.stnormal; 1073 break; 1074 } 1075 case sstmssqlcreateprocedure: 1076 case sstmssqlcreatefunction: 1077 case sstcreatetrigger: 1078 case sstmssqlalterprocedure: 1079 case sstmssqlalterfunction: 1080 case sstmssqlaltertrigger: { 1081 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1082 gcurrentsqlstatement = lcnextsqlstatement; 1083 addTokenToStatement(ast); 1084 gst = EFindSqlStateType.ststoredprocedure; 1085 break; 1086 } 1087 case sstcreateview: 1088 case sstcreatetable: { 1089 1090 boolean readForNewStmt = false; 1091 TSourceToken st1 = ast.searchToken(';', -1); 1092 if (st1 != null) { 1093 TSourceToken st2 = ast.searchToken(TBaseType.rrw_end, -2); 1094 if (st2 != null) { 1095 readForNewStmt = true; 1096 } 1097 } 1098 1099 if (readForNewStmt) { 1100 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1101 gcurrentsqlstatement = lcnextsqlstatement; 1102 addTokenToStatement(ast); 1103 gst = EFindSqlStateType.stsql; 1104 } else { 1105 lcnextsqlstatement = null; 1106 } 1107 break; 1108 } 1109 case sstmssqlDropSecurityPolicy: 1110 case sstmssqlAlterSecurityPolicy: 1111 case sstmssqlCreateSecurityPolicy: 1112 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, false, builder); 1113 gcurrentsqlstatement = lcnextsqlstatement; 1114 addTokenToStatement(ast); 1115 gst = EFindSqlStateType.stsql; 1116 1117 break; 1118 default: { 1119 lcnextsqlstatement = null; 1120 break; 1121 } 1122 } 1123 } 1124 1125 if (gst == EFindSqlStateType.ststoredprocedurebody) 1126 addTokenToStatement(ast); 1127 } 1128 break; 1129 } 1130 } 1131 1132 // last statement 1133 if (TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) { 1134 onRawStatementComplete(parserContext, gcurrentsqlstatement, fparser, null, sqlstatements, true, builder); 1135 } 1136 1137 builder.sqlStatements(this.sqlstatements); 1138 builder.errorCode(errorcount); 1139 builder.errorMessage(errorcount == 0 ? "" : String.format("Extraction completed with %d error(s)", errorcount)); 1140 } 1141}