001package gudusoft.gsqlparser; 002 003import gudusoft.gsqlparser.compiler.TASTEvaluator; 004import gudusoft.gsqlparser.compiler.TContext; 005import gudusoft.gsqlparser.compiler.TGlobalScope; 006import gudusoft.gsqlparser.compiler.TFrame; 007import gudusoft.gsqlparser.nodes.*; 008import gudusoft.gsqlparser.nodes.teradata.TTeradataHelper; 009import gudusoft.gsqlparser.resolver.*; 010import gudusoft.gsqlparser.resolver2.TSQLResolver2; 011import gudusoft.gsqlparser.resolver2.TSQLResolverConfig; 012import gudusoft.gsqlparser.sqlcmds.ISqlCmds; 013import gudusoft.gsqlparser.sqlcmds.SqlCmdsFactory; 014import gudusoft.gsqlparser.sqlenv.TSQLEnv; 015import gudusoft.gsqlparser.stmt.*; 016import gudusoft.gsqlparser.stmt.dax.TDaxEvaluateStmt; 017import gudusoft.gsqlparser.stmt.dax.TDaxExprStmt; 018import gudusoft.gsqlparser.stmt.greenplum.TSlashCommand; 019import gudusoft.gsqlparser.stmt.mssql.TMssqlBlock; 020import gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure; 021import gudusoft.gsqlparser.stmt.mssql.TMssqlExecute; 022import gudusoft.gsqlparser.stmt.mysql.TMySQLSource; 023import gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage; 024import gudusoft.gsqlparser.stmt.oracle.TSqlplusCmdStatement; 025import gudusoft.gsqlparser.stmt.snowflake.TCreateTaskStmt; 026import gudusoft.gsqlparser.stmt.teradata.TTeradataBTEQCmd; 027import gudusoft.gsqlparser.stmt.teradata.TTeradataFastExportCmd; 028import gudusoft.gsqlparser.stmt.teradata.TTeradataFastLoadCmd; 029import gudusoft.gsqlparser.stmt.teradata.TTeradataMultiLoadCmd; 030import gudusoft.gsqlparser.stmt.teradata.utilities.BteqCmdType; 031import gudusoft.gsqlparser.stmt.teradata.utilities.TeradataUtilityType; 032import gudusoft.gsqlparser.util.TSnowflakeParameterChecker; 033import gudusoft.gsqlparser.parser.SqlParser; 034import gudusoft.gsqlparser.parser.ParserContext; 035import gudusoft.gsqlparser.parser.SqlParseResult; 036import gudusoft.gsqlparser.parser.AbstractSqlParser; 037 038 039import java.io.*; 040import java.nio.charset.Charset; 041import java.security.MessageDigest; 042import java.security.NoSuchAlgorithmException; 043import java.text.DateFormat; 044import java.text.ParseException; 045import java.util.*; 046 047import static gudusoft.gsqlparser.ESqlStatementType.*; 048 049 050/** 051 * This is the first class people start to use this SQL parser library. 052 * This class includes a lexer and a parser. The lexer is used to tokenize the input SQL, turn the input SQL text 053 * into a list of source tokens. The parser use this list source token as input, using the grammar rule of the specified 054 * database vendor to check the syntax of the input SQL and build the parse tree of this SQL if there is no syntax error 055 * in the input SQL. 056 * <p></p> 057 * Creating a SQL parser by specifing {@link gudusoft.gsqlparser.EDbObjectType a database vendor}, 058 * then set SQL script text via {@link #setSqltext} method or reading the input SQL from a file via 059 * {@link #setSqlfilename} method. 060 * <p></p> 061 * After that, call one of the following methods to achieve what you need: 062 * <ul> 063 * <li>{@link #tokenizeSqltext}, turns the input SQL into a sequence of token which is the 064 * basic lexis element of SQL syntax. Token is categorized as keyword, identifier, 065 * number, operator, whitespace and other types. All source tokens can be fetched 066 * via the {@link #getSourcetokenlist()} method</li> 067 * 068 * <li>{@link #getrawsqlstatements}, separates the SQL statements in the input SQL script without 069 * doing syntax check, use the {@link #getSqlstatements()} method to get a list of SQL statements 070 * which is the sub-class of {@link TCustomSqlStatement}, get SQL statement type 071 * via the {@link TCustomSqlStatement#sqlstatementtype} field, and string representation of 072 * each SQL statement via the {@link TCustomSqlStatement#toString} method. All source tokens in this SQL statement 073 * is available by using {@link TCustomSqlStatement#sourcetokenlist} filed. 074 * Since no parse tree is built by calling this method, no further detailed information about the SQL statement is available. 075 * </li> 076 * 077 * <li>{@link #parse}, Check syntax of the input SQL, doing some kind of semantic analysis without connecting to 078 * a real database. 079 * This method will do a in-depth analysis of the input SQL such as building the link between table and columns. 080 * The parse tree of the input SQL is available after calling this method. 081 * </li> 082 * </ul> 083 * 084 * The parser checks the syntax of those SQL statements one by one. If syntax error is found in a SQL statement, 085 * an error will be logged, no parse tree will be built for this SQL statement, 086 * the error message can be fetched using the {@link #getErrormessage()} method. 087 * <p></p> 088 * The syntax error in one SQL statement doesn't prevent the parser continue to check the syntax of the next SQL statement. 089 * After checking syntax of all SQL statements, use the {@link #getErrorCount()} method to get the total number of errors. 090 * <p></p> 091 * A syntax error in a SQL stored procedure will cease this parser to check syntax of the rest SQL statements 092 * in this stored procedure. 093 * 094 * <p>Format SQL script can be done after calling {@link #parse()}. 095 * <code> 096 * 097 * int ret = sqlparser.parse(); 098 * if (ret == 0){ 099 * GFmtOpt option = GFmtOptFactory.newInstance(); 100 * String result = FormatterFactory.pp(sqlparser, option); 101 * System.out.println(result); 102 * }else{ 103 * System.out.println(sqlparser.getErrormessage()); 104 * } 105 * 106 * </code> 107 * 108 * <p> After paring SQL script, all parse tree nodes are available for use, some of use cases 109 * are: 110 * <ul> 111 * <li>Table/column impact analysis</li> 112 * <li>SQL rewriting</li> 113 * <li>SQL translate between different databases</li> 114 * <li>SQL migration analysis</li> 115 * <li>Help to anti SQL injection</li> 116 * <li><a href="http://support.sqlparser.com/">More use cases</a></li> 117 * </ul> 118 * 119 * <p>Typically, SQL parse tree nodes generated by this SQL Parser were closely related to SQL 120 * elements defined in database vendor's SQL reference book. here is a brief summary of some 121 * most used SQL elements and corresponding classes defined in this SQL parser. 122 * <ul> 123 * <li>SQL identifier: {@link gudusoft.gsqlparser.nodes.TObjectName}</li> 124 * <li>SQL literal: {@link gudusoft.gsqlparser.nodes.TConstant}</li> 125 * <li>SQL datatype: {@link gudusoft.gsqlparser.nodes.TTypeName}</li> 126 * <li>SQL function: {@link gudusoft.gsqlparser.nodes.TFunctionCall}</li> 127 * <li>SQL constraint: {@link gudusoft.gsqlparser.nodes.TConstraint}</li> 128 * <li>SQL expression/condition: {@link gudusoft.gsqlparser.nodes.TExpression}</li> 129 * <li>SQL select list item: {@link gudusoft.gsqlparser.nodes.TResultColumn}</li> 130 * <li>More: {@link gudusoft.gsqlparser.nodes}</li> 131 * </ul> 132 * 133 * <p> Some major SQL statements: 134 * <ul> 135 * <li>Select: {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement}</li> 136 * <li>Delete: {@link gudusoft.gsqlparser.stmt.TDeleteSqlStatement}</li> 137 * <li>Insert: {@link gudusoft.gsqlparser.stmt.TInsertSqlStatement}</li> 138 * <li>Update: {@link gudusoft.gsqlparser.stmt.TUpdateSqlStatement}</li> 139 * <li>Create table: {@link gudusoft.gsqlparser.stmt.TCreateTableSqlStatement}</li> 140 * <li>More: {@link gudusoft.gsqlparser.stmt}</li> 141 * </ul> 142 * 143 * <p>Stored procedure</p> 144 * <ul> 145 * <li>Create function: {@link gudusoft.gsqlparser.stmt.db2.TDb2CreateFunction }, 146 * {@link gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure}, 147 * {@link gudusoft.gsqlparser.stmt.mysql.TMySQLCreateFunction}, 148 * {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateFunction}</li> 149 * <li>Create procedure: {@link gudusoft.gsqlparser.stmt.db2.TDb2CreateProcedure}, 150 * {@link gudusoft.gsqlparser.stmt.mssql.TMssqlCreateProcedure}, 151 * {@link gudusoft.gsqlparser.stmt.mysql.TMySQLCreateProcedure}, 152 * {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateProcedure}</li> 153 * <li>Create trigger: {@link gudusoft.gsqlparser.stmt.TCreateTriggerStmt}, 154 * {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreateTrigger}</li> 155 * <li>Create package: {@link gudusoft.gsqlparser.stmt.oracle.TPlsqlCreatePackage}</li> 156 * </ul> 157 * 158 * For all available SQL parse tree node classes, please check the API reference. 159 * 160 * 161 */ 162public class TGSqlParser { 163 164 165 166 167 public void setSqlCharset(String sqlCharset) { 168 this.sqlCharset = sqlCharset; 169 } 170 171 public String getSqlCharset() { 172 return sqlCharset; 173 } 174 175 private String sqlCharset = null; 176 177 public static EDbVendor currentDBVendor = EDbVendor.dbvoracle; 178 179 180 /** 181 * Turn the string name of database to dbvendor 182 * <ul> 183 * <li>access: EDbVendor.dbvaccess</li> 184 * <li>ansi: EDbVendor.dbvansi</li> 185 * <li>bigquery: EDbVendor.dbvbigquery</li> 186 * <li>clickhouse: EDbVendor.dbvclickhouse</li> 187 * <li>couchbase: EDbVendor.dbvcouchbase</li> 188 * <li>dax: EDbVendor.dbvdax</li> 189 * <li>db2: EDbVendor.dbvdb2</li> 190 * <li>firebird: EDbVendor.dbvfirebird</li> 191 * <li>generic: EDbVendor.dbvgeneric</li> 192 * <li>greenplum: EDbVendor.dbvgreenplum</li> 193 * <li>hana: EDbVendor.dbvhana</li> 194 * <li>hive: EDbVendor.dbvhive</li> 195 * <li>impala: EDbVendor.dbvimpala</li> 196 * <li>informix: EDbVendor.dbvinformix</li> 197 * <li>mdx: EDbVendor.dbvmdx</li> 198 * <li>mssql or sqlserver: EDbVendor.dbvmssql</li> 199 * <li>mysql: EDbVendor.dbvmysql</li> 200 * <li>netezza: EDbVendor.dbvnetezza</li> 201 * <li>odbc: EDbVendor.dbvodbc</li> 202 * <li>openedge: EDbVendor.dbvopenedge</li> 203 * <li>oracle: EDbVendor.dbvoracle</li> 204 * <li>postgresql or postgres: EDbVendor.dbvpostgresql</li> 205 * <li>redshift: EDbVendor.dbvredshift</li> 206 * <li>snowflake: EDbVendor.dbvsnowflake</li> 207 * <li>sybase: EDbVendor.dbvsybase</li> 208 * <li>teradata: EDbVendor.dbvteradata</li> 209 * <li>vertica: EDbVendor.dbvvertica</li> 210 * </ul> 211 * @param dbVendorName 212 * @return dbvendor 213 */ 214 public static EDbVendor getDBVendorByName(String dbVendorName){ 215 return EDbVendor.valueOfWithDefault(dbVendorName); 216 } 217 218// public void teradataCmds(){ 219// // int cnt = 0; 220// //((TLexerTeradata)getFlexer()). 221//// for(int i=0;i<TLexerTeradata.bteqCmdList.size();i++){ 222//// for(int j=0;j<TLexerTeradata.multiLoadCmdList.size();j++){ 223//// if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.multiLoadCmdList.get(j).toString())){ 224//// System.out.println("multiLoad: "+TLexerTeradata.bteqCmdList.get(i).toString()); 225//// } 226//// } 227//// for(int j=0;j<TLexerTeradata.fastExportCmdList.size();j++){ 228//// if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastExportCmdList.get(j).toString())){ 229//// System.out.println("fastExport: "+TLexerTeradata.bteqCmdList.get(i).toString()); 230//// } 231//// } 232//// for(int j=0;j<TLexerTeradata.fastLoadCmdList.size();j++){ 233//// if (TLexerTeradata.bteqCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastLoadCmdList.get(j).toString())){ 234//// System.out.println("FastLoad: "+TLexerTeradata.bteqCmdList.get(i).toString()); 235//// } 236//// } 237//// } //bteqCmdList 238// 239//// for(int i=0;i<TLexerTeradata.fastLoadCmdList.size();i++){ 240//// for(int j=0;j<TLexerTeradata.multiLoadCmdList.size();j++){ 241//// if (TLexerTeradata.fastLoadCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.multiLoadCmdList.get(j).toString())){ 242//// System.out.println("multiLoad: "+TLexerTeradata.fastLoadCmdList.get(i).toString()); 243//// } 244//// } 245//// for(int j=0;j<TLexerTeradata.fastExportCmdList.size();j++){ 246//// if (TLexerTeradata.fastLoadCmdList.get(i).toString().equalsIgnoreCase(TLexerTeradata.fastExportCmdList.get(j).toString())){ 247//// System.out.println("fastExport: "+TLexerTeradata.fastLoadCmdList.get(i).toString()); 248//// } 249//// } 250//// 251//// } 252// 253// } 254 255 private Stack<TFrame> frameStack = null; 256 257 public Stack<TFrame> getFrameStack(){ 258 if (frameStack == null){ 259 frameStack = new Stack<TFrame>(); 260 } 261 262 return frameStack; 263 } 264 265 public void setFrameStack(Stack<TFrame> frameStack) { 266 this.frameStack = frameStack; 267 } 268 269 void closeFileStream(){ 270 if (streamFromSqlFile != null) { 271 try { 272 streamFromSqlFile.close(); 273 } catch (IOException e) { 274 e.printStackTrace(); 275 } 276 } 277 } 278 279 FileInputStream streamFromSqlFile = null; 280 InputStreamReader sqlStreamReader = null; 281 /** 282 * A sequence of source tokens created by the lexer after tokenize the input SQL 283 * 284 * @return a sequence of source tokens 285 */ 286 public TSourceTokenList getSourcetokenlist() { 287 return sourcetokenlist; 288 } 289 290 /** 291 * A list of SQL statements created by the parser. 292 * If this list is created after calling the {@link #getrawsqlstatements} method, the syntax of each SQL statement 293 * is not checked and the parse tree of each statement is not created. If the {@link #parse} method is called to build 294 * this SQL statement list, then every thing is ready. 295 * 296 * @return a list of SQL statement 297 */ 298 public TStatementList getSqlstatements() { 299 return sqlstatements; 300 } 301 302 enum stored_procedure_status {start,is_as,body,bodyend,end, cursor_declare}; 303 enum stored_procedure_type {function,procedure,package_spec,package_body, block_with_begin,block_with_declare, 304 create_trigger,create_library,cursor_in_package_spec,others}; 305 306 static final int stored_procedure_nested_level = 1024; 307 308 /** 309 ** The input SQL Text. 310 ** If {@link #sqlfilename} is specified, then this field will be ignored. 311 */ 312 public String sqltext; 313 314 /** 315 * set the input SQL text, If {@link #sqlfilename} is specified before this method, the parser will using 316 * the SQL text in this field instead of read SQL from {@link #sqlfilename}. 317 * 318 * @param sqltext the input SQL text 319 */ 320 public void setSqltext(String sqltext) { 321 this.sqltext = sqltext; 322 this.sqlfilename = ""; 323 this.sqlInputStream = null; 324 } 325 326 /** 327 * The SQL text that being processed. 328 * 329 * @return the SQL text that being processed 330 */ 331 public String getSqltext() { 332 return sqltext; 333 } 334 335 336 /** 337 ** The input SQL will be read from this file 338 * 339 ** If field is specified, then {@link #sqltext} will be ignored. 340 * This must be the full path to the file, relative path doesn't work. 341 */ 342 public String sqlfilename; 343 344 345 /** 346 * set the filename from which the input SQL will be read. 347 * 348 * @param sqlfilename the SQL file name from which the input SQL will be read 349 */ 350 public void setSqlfilename(String sqlfilename) { 351 this.sqlfilename = sqlfilename; 352 this.sqltext = ""; 353 this.sqlInputStream = null; 354 } 355 356 /** 357 * The input SQL filename. This parser can process the unicode encoded SQL file. 358 * 359 * @return the input SQL filename 360 */ 361 public String getSqlfilename() { 362 return sqlfilename; 363 } 364 365 /** 366 * set the InputStream from which SQL will be read. 367 * If this method is called, {@link #sqlfilename} and {@link #sqltext} will be ignored. 368 * 369 * @param sqlInputStream the InputStream from which SQL will be read 370 */ 371 public void setSqlInputStream(InputStream sqlInputStream) { 372 if (sqlInputStream instanceof BufferedInputStream){ 373 this.sqlInputStream = (BufferedInputStream)sqlInputStream; 374 }else{ 375 this.sqlInputStream = new BufferedInputStream(sqlInputStream); 376 } 377 378 this.sqlfilename = ""; 379 this.sqltext = ""; 380 } 381 382 private BufferedInputStream sqlInputStream; 383 384 /** 385 * the InputStream from which SQL will be read 386 * @return the InputStream from which SQL will be read 387 */ 388 public InputStream getSqlInputStream() { 389 return sqlInputStream; 390 } 391 392 /** 393 ** Tokens generated by lexer from the input SQL script. 394 * Tokens are always available even if there are syntax errors in input the SQL script. 395 */ 396 public TSourceTokenList sourcetokenlist; 397 398 /** 399 ** SQL statements generated by this parser from the input SQL script. 400 * statements are always available even if there are syntax errors in input SQL script. 401 * if there is no syntax error in a statement, you can access the parse tree of the statement to fetch more information 402 * such as tables, columns, etc. 403 */ 404 public TStatementList sqlstatements; 405 406 /** 407 * The TSQLResolver2 instance used for name resolution when ENABLE_RESOLVER2 is set. 408 * Unlike TSQLResolver which is created as a local variable, TSQLResolver2 is stored 409 * as a property so users can retrieve name resolution results after parsing. 410 * 411 * Usage: 412 * <pre> 413 * TBaseType.setEnableResolver(false); // Disable old resolver 414 * TBaseType.setEnableResolver2(true); // Enable new resolver 415 * 416 * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle); 417 * parser.sqltext = sqlContent; 418 * int ret = parser.parse(); 419 * 420 * // Access resolver2 results 421 * TSQLResolver2 resolver2 = parser.getResolver2(); 422 * if (resolver2 != null) { 423 * // Use TSQLResolver2ResultFormatter to generate output 424 * TSQLResolver2ResultFormatter formatter = new TSQLResolver2ResultFormatter(resolver2, config); 425 * String result = formatter.format(); 426 * } 427 * </pre> 428 */ 429 private TSQLResolver2 resolver2; 430 431 /** 432 * Get the TSQLResolver2 instance used for name resolution. 433 * Returns null if resolver2 was not used or if parsing failed. 434 * 435 * @return the TSQLResolver2 instance or null 436 */ 437 public TSQLResolver2 getResolver2() { 438 return resolver2; 439 } 440 441 /** 442 * The resolver type to use for name resolution. 443 * Default is EResolverType.DEFAULT which uses TBaseType settings. 444 */ 445 private EResolverType resolverType = EResolverType.DEFAULT; 446 447 /** 448 * Get the resolver type used for name resolution. 449 * 450 * @return the resolver type 451 */ 452 public EResolverType getResolverType() { 453 return resolverType; 454 } 455 456 /** 457 * Set the resolver type to use for name resolution. 458 * 459 * <p>This instance-level setting takes precedence over global TBaseType settings. 460 * When set to DEFAULT (the default value), behavior is determined by 461 * TBaseType.isEnableResolver() and TBaseType.isEnableResolver2().</p> 462 * 463 * <h3>Usage Example:</h3> 464 * <pre> 465 * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle); 466 * parser.setResolverType(EResolverType.RESOLVER2); // Use new resolver 467 * parser.sqltext = "SELECT * FROM employees"; 468 * parser.parse(); 469 * 470 * // Access resolver2 results 471 * TSQLResolver2 resolver = parser.getResolver2(); 472 * </pre> 473 * 474 * @param resolverType the resolver type to use 475 * @see EResolverType 476 */ 477 public void setResolverType(EResolverType resolverType) { 478 this.resolverType = resolverType != null ? resolverType : EResolverType.DEFAULT; 479 } 480 481 /** 482 * Optional configuration for TSQLResolver2. 483 * If null, a default configuration will be created during parsing. 484 */ 485 private TSQLResolverConfig resolver2Config; 486 487 /** 488 * Get the TSQLResolverConfig used for resolver2. 489 * Returns null if not explicitly set (default config will be used during parsing). 490 * 491 * @return the resolver2 config or null 492 */ 493 public TSQLResolverConfig getResolver2Config() { 494 return resolver2Config; 495 } 496 497 /** 498 * Set the TSQLResolverConfig to use for resolver2. 499 * 500 * <p>This allows customizing resolver2 behavior such as:</p> 501 * <ul> 502 * <li>guessColumnStrategy - how to handle ambiguous columns</li> 503 * <li>legacyCompatibilityEnabled - sync results to legacy structures</li> 504 * <li>maxIterations - maximum iterations for iterative resolution</li> 505 * </ul> 506 * 507 * <p>If not set, a default configuration will be created during parsing 508 * with the database vendor automatically set.</p> 509 * 510 * <h3>Usage Example:</h3> 511 * <pre> 512 * TGSqlParser parser = new TGSqlParser(EDbVendor.dbvoracle); 513 * parser.setResolverType(EResolverType.RESOLVER2); 514 * 515 * // Configure resolver2 to not pick ambiguous columns 516 * TSQLResolverConfig config = new TSQLResolverConfig(); 517 * config.setGuessColumnStrategy(TSQLResolverConfig.GUESS_COLUMN_STRATEGY_NOT_PICKUP); 518 * parser.setResolver2Config(config); 519 * 520 * parser.sqltext = "SELECT id FROM users, orders"; 521 * parser.parse(); 522 * </pre> 523 * 524 * @param config the resolver2 configuration, or null for default 525 * @see TSQLResolverConfig 526 */ 527 public void setResolver2Config(TSQLResolverConfig config) { 528 this.resolver2Config = config; 529 } 530 531 /** 532 * The array of syntax error generated by the parser during checking the syntax of the input SQL, 533 * element of this list is type of {@link TSyntaxError} 534 * 535 * @return the array of errors 536 */ 537 public ArrayList <TSyntaxError> getSyntaxErrors() { 538 return syntaxErrors; 539 } 540 541 private ArrayList <TSyntaxError> syntaxErrors; 542 543// public ArrayList<TSyntaxError> getSyntaxHints() { 544// return syntaxHints; 545// } 546 547 //private ArrayList <TSyntaxError> syntaxHints; 548 549 /** 550 * The database vendor specified when creating this parser. 551 * The grammar rule of this database vendor will be used to validate the syntax of the input SQL. 552 * 553 * @return the database vendor 554 */ 555 public EDbVendor getDbVendor() { 556 return dbVendor; 557 } 558 559 /** 560 * @deprecated As of v1.4.3.4 561 * enable GSP to parse the rest of sql statements inside stored procedure 562 * when a SQL statement in the stored procedure cannot be parsed 563 * 564 * <p>Available to parse sybase stored procedure currently. 565 * 566 * @param enablePartialParsing set true to enable this partial parsing, default is false 567 */ 568 public void setEnablePartialParsing(boolean enablePartialParsing) { 569 this.enablePartialParsing = enablePartialParsing; 570 } 571 572 /** 573 * enable GSP to parse the rest of sql statements inside stored procedure 574 * when a SQL statement in the stored procedure cannot be parsed 575 * 576 * <p>Available to parse sybase stored procedure currently. 577 * 578 * <p> default is false; 579 * 580 * @deprecated As of v1.4.3.4 581 */ 582 private boolean isEnablePartialParsing() { 583 584 return enablePartialParsing; 585 } 586 587 private boolean enablePartialParsing = false; 588 589 private boolean isSinglePLBlock = false; 590 591 public void setSinglePLBlock(boolean singlePLBlock) { 592 isSinglePLBlock = singlePLBlock; 593 } 594 595 private static String userName; 596 private static String machineId = null; 597 private static String licenseKey; 598 private static String licenseType; 599 private static boolean licenseOK = false; 600 private static String licenseMessage; 601 602 /** 603 * Not used. 604 * 605 * @return the user name 606 */ 607 public static String getUserName() { 608 return userName; 609 } 610 611 /** 612 * Not used. 613 * 614 * @return the machine id 615 */ 616 public static String getMachineId() { 617 618 return machineId; 619 } 620 621 /** 622 * Not used. 623 * 624 * @return the license message 625 */ 626 public static String getLicenseMessage() { 627 return licenseMessage; 628 } 629 630 631 static { 632 licenseOK = validateLicense(); 633 } 634 635 /** 636 * Not used. 637 * 638 * @return trial license or developer license or distribution license 639 */ 640 public static String getLicenseType() { 641 return licenseType; 642 } 643 644 private EDbVendor dbVendor; 645 private String errormessage; 646 647 /** 648 * The lexer which is used to tokenize the input SQL. 649 * For delegated vendors (MSSQL), lazily creates the vendor parser to get its lexer. 650 * 651 * @return the lexer 652 */ 653 public TCustomLexer getFlexer() { 654 if (flexer == null) { 655 // Lazily create vendor parser to get its lexer 656 SqlParser vp = getOrCreateVendorParser(); 657 if (vp instanceof gudusoft.gsqlparser.parser.MssqlSqlParser) { 658 // Cache the flexer from vendor parser 659 flexer = ((gudusoft.gsqlparser.parser.MssqlSqlParser) vp).flexer; 660 } else if (vp instanceof gudusoft.gsqlparser.parser.MySqlSqlParser) { 661 // Cache the flexer from vendor parser 662 flexer = ((gudusoft.gsqlparser.parser.MySqlSqlParser) vp).flexer; 663 } else if (vp instanceof gudusoft.gsqlparser.parser.PostgreSqlParser) { 664 // Cache the flexer from vendor parser 665 flexer = ((gudusoft.gsqlparser.parser.PostgreSqlParser) vp).flexer; 666 } else if (vp instanceof gudusoft.gsqlparser.parser.OracleSqlParser) { 667 // Cache the flexer from vendor parser 668 flexer = ((gudusoft.gsqlparser.parser.OracleSqlParser) vp).flexer; 669 } else if (vp instanceof gudusoft.gsqlparser.parser.BigQuerySqlParser) { 670 // Cache the flexer from vendor parser 671 flexer = ((gudusoft.gsqlparser.parser.BigQuerySqlParser) vp).flexer; 672 } else if (vp instanceof gudusoft.gsqlparser.parser.AthenaSqlParser) { 673 // Cache the flexer from vendor parser 674 flexer = ((gudusoft.gsqlparser.parser.AthenaSqlParser) vp).flexer; 675 } else if (vp instanceof gudusoft.gsqlparser.parser.CouchbaseSqlParser) { 676 // Cache the flexer from vendor parser 677 flexer = ((gudusoft.gsqlparser.parser.CouchbaseSqlParser) vp).flexer; 678 } else if (vp instanceof gudusoft.gsqlparser.parser.DatabricksSqlParser) { 679 // Cache the flexer from vendor parser 680 flexer = ((gudusoft.gsqlparser.parser.DatabricksSqlParser) vp).flexer; 681 } else if (vp instanceof gudusoft.gsqlparser.parser.DaxSqlParser) { 682 // Cache the flexer from vendor parser 683 flexer = ((gudusoft.gsqlparser.parser.DaxSqlParser) vp).flexer; 684 } else if (vp instanceof gudusoft.gsqlparser.parser.Db2SqlParser) { 685 // Cache the flexer from vendor parser 686 flexer = ((gudusoft.gsqlparser.parser.Db2SqlParser) vp).flexer; 687 } else if (vp instanceof gudusoft.gsqlparser.parser.GaussDbSqlParser) { 688 // Cache the flexer from vendor parser 689 flexer = ((gudusoft.gsqlparser.parser.GaussDbSqlParser) vp).flexer; 690 } else if (vp instanceof gudusoft.gsqlparser.parser.GreenplumSqlParser) { 691 // Cache the flexer from vendor parser 692 flexer = ((gudusoft.gsqlparser.parser.GreenplumSqlParser) vp).flexer; 693 } else if (vp instanceof gudusoft.gsqlparser.parser.HiveSqlParser) { 694 // Cache the flexer from vendor parser 695 flexer = ((gudusoft.gsqlparser.parser.HiveSqlParser) vp).flexer; 696 } else if (vp instanceof gudusoft.gsqlparser.parser.HanaSqlParser) { 697 // Cache the flexer from vendor parser 698 flexer = ((gudusoft.gsqlparser.parser.HanaSqlParser) vp).flexer; 699 } else if (vp instanceof gudusoft.gsqlparser.parser.ImpalaSqlParser) { 700 // Cache the flexer from vendor parser 701 flexer = ((gudusoft.gsqlparser.parser.ImpalaSqlParser) vp).flexer; 702 } else if (vp instanceof gudusoft.gsqlparser.parser.InformixSqlParser) { 703 // Cache the flexer from vendor parser 704 flexer = ((gudusoft.gsqlparser.parser.InformixSqlParser) vp).flexer; 705 } else if (vp instanceof gudusoft.gsqlparser.parser.MdxSqlParser) { 706 // Cache the flexer from vendor parser 707 flexer = ((gudusoft.gsqlparser.parser.MdxSqlParser) vp).flexer; 708 } else if (vp instanceof gudusoft.gsqlparser.parser.NetezzaSqlParser) { 709 // Cache the flexer from vendor parser 710 flexer = ((gudusoft.gsqlparser.parser.NetezzaSqlParser) vp).flexer; 711 } else if (vp instanceof gudusoft.gsqlparser.parser.OdbcSqlParser) { 712 // Cache the flexer from vendor parser 713 flexer = ((gudusoft.gsqlparser.parser.OdbcSqlParser) vp).flexer; 714 } else if (vp instanceof gudusoft.gsqlparser.parser.OpenEdgeSqlParser) { 715 // Cache the flexer from vendor parser 716 flexer = ((gudusoft.gsqlparser.parser.OpenEdgeSqlParser) vp).flexer; 717 } else if (vp instanceof gudusoft.gsqlparser.parser.PrestoSqlParser) { 718 // Cache the flexer from vendor parser 719 flexer = ((gudusoft.gsqlparser.parser.PrestoSqlParser) vp).flexer; 720 } else if (vp instanceof gudusoft.gsqlparser.parser.RedshiftSqlParser) { 721 // Cache the flexer from vendor parser 722 flexer = ((gudusoft.gsqlparser.parser.RedshiftSqlParser) vp).flexer; 723 } else if (vp instanceof gudusoft.gsqlparser.parser.SnowflakeSqlParser) { 724 // Cache the flexer from vendor parser 725 flexer = ((gudusoft.gsqlparser.parser.SnowflakeSqlParser) vp).flexer; 726 } else if (vp instanceof gudusoft.gsqlparser.parser.SoqlSqlParser) { 727 // Cache the flexer from vendor parser 728 flexer = ((gudusoft.gsqlparser.parser.SoqlSqlParser) vp).flexer; 729 } else if (vp instanceof gudusoft.gsqlparser.parser.SparksqlSqlParser) { 730 // Cache the flexer from vendor parser 731 flexer = ((gudusoft.gsqlparser.parser.SparksqlSqlParser) vp).flexer; 732 } else if (vp instanceof gudusoft.gsqlparser.parser.SybaseSqlParser) { 733 // Cache the flexer from vendor parser 734 flexer = ((gudusoft.gsqlparser.parser.SybaseSqlParser) vp).flexer; 735 } else if (vp instanceof gudusoft.gsqlparser.parser.VerticaSqlParser) { 736 // Cache the flexer from vendor parser 737 flexer = ((gudusoft.gsqlparser.parser.VerticaSqlParser) vp).flexer; 738 } 739 } 740 return flexer; 741 } 742 743 private TCustomLexer flexer; 744 745 TCustomParser fparser,fplsqlparser; 746 747 // Cached vendor-specific parser for delegated parsing (MSSQL, etc.) 748 // Created lazily in getFlexer() and reused in parse() 749 private SqlParser vendorParser; 750 751 BufferedReader finputstream = null; //used by lexer 752 TCustomSqlStatement gcurrentsqlstatement,nextStmt; 753 // Vendor-specific SQL command resolver 754 ISqlCmds sqlcmds; 755 756 HashMap sqlpluskeywordList; 757 758 char delimiterchar; 759 String defaultDelimiterStr; 760 761 /** 762 * Returns the delimiter character used to separate SQL statements. 763 * Uses the flexer's delimiter if available (lexer-dependent), otherwise falls back to parser's value. 764 * @return the delimiter character 765 */ 766 public char getDelimiterChar() { 767 if (flexer != null) { 768 return flexer.delimiterchar; 769 } 770 return delimiterchar; 771 } 772 773 private ISQLStatementHandle sqlStatementHandle = null; 774 775 public void setSqlStatementHandle(ISQLStatementHandle sqlStatementHandle) { 776 this.sqlStatementHandle = sqlStatementHandle; 777 } 778 779 private ITokenHandle tokenHandle = null; 780 781 /** 782 * Set an event handler which will be fired when a new source token is created by the lexer during tokenize the 783 * input SQL. 784 * 785 * @param tokenHandle the event handler to process the new created source token 786 */ 787 public void setTokenHandle(ITokenHandle tokenHandle) { 788 this.tokenHandle = tokenHandle; 789 } 790 791 private ITokenListHandle tokenListHandle = null; 792 793 public void setTokenListHandle(ITokenListHandle tokenListHandle) { 794 this.tokenListHandle = tokenListHandle; 795 } 796 797 private IMetaDatabase metaDatabase = null; 798 799 /** 800 * @deprecated As of v2.0.3.1, please use {@link #getSqlEnv()} instead 801 * 802 * set an instance of a class which implement the interface: {@link IMetaDatabase}. 803 * The parser will call {@link IMetaDatabase#checkColumn} method when it needs to know 804 * whether a column is belonged to a table. 805 * <p></p> 806 * The class that implements the interface: {@link IMetaDatabase} usually fetch the metadata from the database 807 * by connecting to a database instance. 808 * <p></p> 809 * If the class is not provided, the parser has to guess the relationship between a un-qualified column and table 810 * in the input SQL which may lead to a un-determined result between the column and table. 811 * 812 * @param metaDatabase a new instance of the class which implements the {@link IMetaDatabase} interface 813 * @see IMetaDatabase 814 */ 815 public void setMetaDatabase(IMetaDatabase metaDatabase) { 816 this.metaDatabase = metaDatabase; 817 } 818 819 /** 820 * @deprecated As of v2.0.3.1, please use {@link #getSqlEnv()} instead 821 * 822 * a new instance of the class which implements the {@link IMetaDatabase} interface 823 * 824 * @return a new instance of the class which implements the {@link IMetaDatabase} interface 825 * @see #setMetaDatabase 826 */ 827 public IMetaDatabase getMetaDatabase() { 828 829 return metaDatabase; 830 } 831 832 /** 833 * Not used. 834 * 835 */ 836 public void freeParseTable() { 837 flexer.yystack = null; 838 flexer.yytextbuf = null; 839 flexer.buf = null; 840 841// TLexerOracle.yyk = null; 842// TLexerOracle.yykl = null; 843// TLexerOracle.yykh = null; 844// TLexerOracle.yym = null; 845// TLexerOracle.yyml = null; 846// TLexerOracle.yymh = null; 847// TLexerOracle.yyt = null; 848// TLexerOracle.yytl = null; 849// TLexerOracle.yyth = null; 850// TParserOracleSql.yyah = null; 851// TParserOracleSql.yyal = null; 852// TParserOracleSql.yygh = null; 853// TParserOracleSql.yygl = null; 854// TParserOracleSql.yyd = null; 855// TParserOracleSql.yya_sym= null; 856// TParserOracleSql.yya_act= null; 857// TParserOracleSql.yyr_len= null; 858// TParserOracleSql.yyr_sym= null; 859// TParserOracleSql.yyg_sym= null; 860// TParserOracleSql.yyg_act= null; 861// 862// TParserOraclePLSql.yyah = null; 863// TParserOraclePLSql.yyal = null; 864// TParserOraclePLSql.yygh = null; 865// TParserOraclePLSql.yygl = null; 866// TParserOraclePLSql.yyd = null; 867// TParserOraclePLSql.yya_sym= null; 868// TParserOraclePLSql.yya_act= null; 869// TParserOraclePLSql.yyr_len= null; 870// TParserOraclePLSql.yyr_sym= null; 871// TParserOraclePLSql.yyg_sym= null; 872// TParserOraclePLSql.yyg_act= null; 873// 874// TLexerMssql.yyk = null; 875// TLexerMssql.yykl = null; 876// TLexerMssql.yykh = null; 877// TLexerMssql.yym = null; 878// TLexerMssql.yyml = null; 879// TLexerMssql.yymh = null; 880// TLexerMssql.yyt = null; 881// TLexerMssql.yytl = null; 882// TLexerMssql.yyth = null; 883// TParserMssqlSql.yyah = null; 884// TParserMssqlSql.yyal = null; 885// TParserMssqlSql.yygh = null; 886// TParserMssqlSql.yygl = null; 887// TParserMssqlSql.yyd = null; 888// TParserMssqlSql.yya_sym= null; 889// TParserMssqlSql.yya_act= null; 890// TParserMssqlSql.yyr_len= null; 891// TParserMssqlSql.yyr_sym= null; 892// TParserMssqlSql.yyg_sym= null; 893// TParserMssqlSql.yyg_act= null; 894// 895// TLexerMysql.yyk = null; 896// TLexerMysql.yykl = null; 897// TLexerMysql.yykh = null; 898// TLexerMysql.yym = null; 899// TLexerMysql.yyml = null; 900// TLexerMysql.yymh = null; 901// TLexerMysql.yyt = null; 902// TLexerMysql.yytl = null; 903// TLexerMysql.yyth = null; 904// TParserMysqlSql.yyah = null; 905// TParserMysqlSql.yyal = null; 906// TParserMysqlSql.yygh = null; 907// TParserMysqlSql.yygl = null; 908// TParserMysqlSql.yyd = null; 909// TParserMysqlSql.yya_sym= null; 910// TParserMysqlSql.yya_act= null; 911// TParserMysqlSql.yyr_len= null; 912// TParserMysqlSql.yyr_sym= null; 913// TParserMysqlSql.yyg_sym= null; 914// TParserMysqlSql.yyg_act= null; 915 } 916 917 /** 918 * Class constructor, create a new instance of the parser by setting the database vendor 919 * 920 * @param pdbvendor the database vendor whose grammar rule will be used to validate the syntax of the input SQL 921 */ 922 public TGSqlParser(EDbVendor pdbvendor) { 923 dbVendor = pdbvendor; 924 sqltext = ""; 925 sqlfilename = ""; 926 927 delimiterchar = ';'; 928 defaultDelimiterStr = ";"; 929 switch(pdbvendor){ 930 case dbvmssql: 931 case dbvazuresql: 932 // MSSQL and Azure SQL are delegated to MssqlSqlParser for tokenization 933 // - flexer is accessed via getFlexer() which lazily creates MssqlSqlParser 934 // - fparser is set in doDelegatedRawParse() from vendor parser result 935 if (pdbvendor == EDbVendor.dbvazuresql) { 936 dbVendor = EDbVendor.dbvmssql; 937 } 938 break; 939 case dbvaccess: 940 // Access uses MSSQL lexer/parser but is NOT delegated 941 if (TBaseType.enterprise_edition || (!TBaseType.full_edition) || TBaseType.sqlserver_edition || TBaseType.azuresql_edition) { 942 flexer = new TLexerMssql(); 943 flexer.delimiterchar = delimiterchar; 944 flexer.defaultDelimiterStr = defaultDelimiterStr; 945 fparser = new TParserMssqlSql(null); 946 fparser.lexer = flexer; 947 } 948 break; 949 case dbvsybase:{ 950 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sybase_edition){ 951 flexer = new TLexerSybase(); 952 flexer.delimiterchar = delimiterchar; 953 flexer.defaultDelimiterStr = defaultDelimiterStr; 954 fparser = new TParserSybase(null); 955 fparser.lexer = flexer; 956 } 957 enablePartialParsing = false; 958 break; 959 } 960 case dbvinformix:{ 961 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.informix_edition){ 962 flexer = new TLexerInformix(); 963 flexer.delimiterchar = delimiterchar; 964 flexer.defaultDelimiterStr = defaultDelimiterStr; 965 fparser = new TParserInformix(null); 966 fparser.lexer = flexer; 967 } 968 enablePartialParsing = false; 969 break; 970 } 971 case dbvoracle: 972 // Oracle is delegated to OracleSqlParser for tokenization and parsing 973 // - flexer is accessed via getFlexer() which lazily creates OracleSqlParser 974 // - fparser and fplsqlparser are set in doDelegatedRawParse() from vendor parser result 975 delimiterchar = '/'; 976 break; 977 case dbvdb2 :{ 978 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.db2_edition){ 979 delimiterchar = '@'; 980 flexer = new TLexerDb2(); 981 flexer.delimiterchar = delimiterchar; 982 flexer.defaultDelimiterStr = defaultDelimiterStr; 983 fparser = new TParserDb2Sql(null); 984 fparser.lexer = flexer; 985 } 986 break; 987 } 988 case dbvmysql :{ 989 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.mysql_edition){ 990 delimiterchar = '$'; 991 defaultDelimiterStr = "$"; 992 flexer = new TLexerMysql(); 993 flexer.delimiterchar = delimiterchar; 994 flexer.defaultDelimiterStr = defaultDelimiterStr; 995 fparser = new TParserMysqlSql(null); 996 fparser.lexer = flexer; 997 } 998 break; 999 } 1000 case dbvteradata :{ 1001 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.teradata_edition){ 1002 delimiterchar = '/'; 1003 flexer = new TLexerTeradata(); 1004 flexer.delimiterchar = delimiterchar; 1005 flexer.defaultDelimiterStr = defaultDelimiterStr; 1006 fparser = new TParserTeradata(null); 1007 fparser.lexer = flexer; 1008 } 1009 break; 1010 } 1011 case dbvpostgresql:{ 1012 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.postgresql_edition){ 1013 delimiterchar = '/'; 1014 flexer = new TLexerPostgresql(); 1015 flexer.delimiterchar = delimiterchar; 1016 flexer.defaultDelimiterStr = defaultDelimiterStr; 1017 fparser = new TParserPostgresql(null); 1018 fparser.lexer = flexer; 1019 } 1020 break; 1021 } 1022 case dbvredshift:{ 1023 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.redshift_edition){ 1024 delimiterchar = '/'; 1025 flexer = new TLexerRedshift(); 1026 flexer.delimiterchar = delimiterchar; 1027 flexer.defaultDelimiterStr = defaultDelimiterStr; 1028 fparser = new TParserRedshift(null); 1029 fparser.lexer = flexer; 1030 } 1031 break; 1032 } 1033 case dbvgreenplum:{ 1034 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.greenplum_edition){ 1035 delimiterchar = '/'; 1036 flexer = new TLexerGreenplum(); 1037 flexer.delimiterchar = delimiterchar; 1038 flexer.defaultDelimiterStr = defaultDelimiterStr; 1039 fparser = new TParserGreenplum(null); 1040 fparser.lexer = flexer; 1041 } 1042 break; 1043 } 1044 case dbvmdx:{ 1045 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.mdx_edition){ 1046 delimiterchar = ';'; 1047 flexer = new TLexerMdx(); 1048 flexer.delimiterchar = delimiterchar; 1049 flexer.defaultDelimiterStr = defaultDelimiterStr; 1050 fparser = new TParserMdx(null); 1051 fparser.lexer = flexer; 1052 } 1053 break; 1054 } 1055 case dbvnetezza:{ 1056 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.netezza_edition){ 1057 delimiterchar = ';'; 1058 flexer = new TLexerNetezza(); 1059 flexer.delimiterchar = delimiterchar; 1060 flexer.defaultDelimiterStr = defaultDelimiterStr; 1061 fparser = new TParserNetezza(null); 1062 fparser.lexer = flexer; 1063 } 1064 break; 1065 } 1066 case dbvhive:{ 1067 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.hive_edition){ 1068 delimiterchar = ';'; 1069 flexer = new TLexerHive(); 1070 flexer.delimiterchar = delimiterchar; 1071 flexer.defaultDelimiterStr = defaultDelimiterStr; 1072 fparser = new TParserHive(null); 1073 fparser.lexer = flexer; 1074 } 1075 break; 1076 } 1077 case dbvimpala:{ 1078 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.impala_edition){ 1079 delimiterchar = ';'; 1080 flexer = new TLexerImpala(); 1081 flexer.delimiterchar = delimiterchar; 1082 flexer.defaultDelimiterStr = defaultDelimiterStr; 1083 fparser = new TParserImpala(null); 1084 fparser.lexer = flexer; 1085 } 1086 break; 1087 } 1088 case dbvhana:{ 1089 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.hana_edition){ 1090 delimiterchar = ';'; 1091 flexer = new TLexerHana(); 1092 flexer.delimiterchar = delimiterchar; 1093 flexer.defaultDelimiterStr = defaultDelimiterStr; 1094 fparser = new TParserHana(null); 1095 fparser.lexer = flexer; 1096 } 1097 break; 1098 } 1099 case dbvdax:{ 1100 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.dax_edition){ 1101 delimiterchar = ';'; 1102 flexer = new TLexerDax(); 1103 flexer.delimiterchar = delimiterchar; 1104 flexer.defaultDelimiterStr = defaultDelimiterStr; 1105 fparser = new TParserDax(null); 1106 fparser.lexer = flexer; 1107 } 1108 break; 1109 } 1110 case dbvodbc:{ 1111 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.odbc_edition){ 1112 delimiterchar = ';'; 1113 flexer = new TLexerOdbc(); 1114 flexer.delimiterchar = delimiterchar; 1115 flexer.defaultDelimiterStr = defaultDelimiterStr; 1116 fparser = new TParserOdbc(null); 1117 fparser.lexer = flexer; 1118 } 1119 break; 1120 } 1121 case dbvvertica:{ 1122 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.vertica_edition){ 1123 delimiterchar = ';'; 1124 flexer = new TLexerVertica(); 1125 flexer.delimiterchar = delimiterchar; 1126 flexer.defaultDelimiterStr = defaultDelimiterStr; 1127 fparser = new TParserVertica(null); 1128 fparser.lexer = flexer; 1129 } 1130 break; 1131 } 1132 case dbvopenedge:{ 1133 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.openedge_edition){ 1134 delimiterchar = ';'; 1135 flexer = new TLexerOpenedge(); 1136 flexer.delimiterchar = delimiterchar; 1137 flexer.defaultDelimiterStr = defaultDelimiterStr; 1138 fparser = new TParserOpenedge(null); 1139 fparser.lexer = flexer; 1140 } 1141 break; 1142 } 1143 case dbvcouchbase:{ 1144 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.couchbase_edition){ 1145 delimiterchar = ';'; 1146 flexer = new TLexerCouchbase(); 1147 flexer.delimiterchar = delimiterchar; 1148 flexer.defaultDelimiterStr = defaultDelimiterStr; 1149 fparser = new TParserCouchbase(null); 1150 fparser.lexer = flexer; 1151 } 1152 break; 1153 } 1154 case dbvsnowflake:{ 1155 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.snowflake_edition){ 1156 delimiterchar = ';'; 1157 flexer = new TLexerSnowflake(); 1158 flexer.delimiterchar = delimiterchar; 1159 flexer.defaultDelimiterStr = defaultDelimiterStr; 1160 fparser = new TParserSnowflake(null); 1161 fparser.lexer = flexer; 1162 } 1163 break; 1164 } 1165 case dbvbigquery:{ 1166 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.bigquery_edition){ 1167 delimiterchar = ';'; 1168 flexer = new TLexerBigquery(); 1169 flexer.delimiterchar = delimiterchar; 1170 flexer.defaultDelimiterStr = defaultDelimiterStr; 1171 fparser = new TParserBigquery(null); 1172 fparser.lexer = flexer; 1173 } 1174 break; 1175 } 1176 case dbvclickhouse:{ 1177 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.clickhouse_edition){ 1178 delimiterchar = '/'; 1179 flexer = new TLexerClickhouse(); 1180 flexer.delimiterchar = delimiterchar; 1181 flexer.defaultDelimiterStr = defaultDelimiterStr; 1182 fparser = new TParserClickhouse(null); 1183 fparser.lexer = flexer; 1184 } 1185 break; 1186 } 1187 case dbvansi: 1188 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.ansi_edition){ 1189 delimiterchar = ';'; 1190 flexer = new TLexerAnsi(); 1191 flexer.delimiterchar = delimiterchar; 1192 flexer.defaultDelimiterStr = defaultDelimiterStr; 1193 fparser = new TParserAnsi(null); 1194 fparser.lexer = flexer; 1195 } 1196 break; 1197 case dbvgeneric: { 1198 if (TBaseType.enterprise_edition || (!TBaseType.full_edition) || TBaseType.generic_edition) { 1199 flexer = new TLexerMssql(); 1200 flexer.delimiterchar = delimiterchar; 1201 flexer.defaultDelimiterStr = defaultDelimiterStr; 1202 fparser = new TParserMssqlSql(null); 1203 fparser.lexer = flexer; 1204 } 1205 break; 1206 } 1207 case dbvsoql:{ 1208 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.soql_edition){ 1209 delimiterchar = ';'; 1210 flexer = new TLexerSoql(); 1211 flexer.delimiterchar = delimiterchar; 1212 flexer.defaultDelimiterStr = defaultDelimiterStr; 1213 fparser = new TParserSoql(null); 1214 fparser.lexer = flexer; 1215 } 1216 break; 1217 } 1218 case dbvsparksql:{ 1219 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sparksql_edition){ 1220 delimiterchar = ';'; 1221 flexer = new TLexerSparksql(); 1222 flexer.delimiterchar = delimiterchar; 1223 flexer.defaultDelimiterStr = defaultDelimiterStr; 1224 fparser = new TParserSparksql(null); 1225 fparser.lexer = flexer; 1226 } 1227 break; 1228 } 1229 case dbvathena: 1230 { 1231 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.athena_edition){ 1232 delimiterchar = ';'; 1233 flexer = new TLexerathena(); 1234 flexer.delimiterchar = delimiterchar; 1235 flexer.defaultDelimiterStr = defaultDelimiterStr; 1236 fparser = new TParserAthena(null); 1237 fparser.lexer = flexer; 1238 } 1239 break; 1240 } 1241 case dbvpresto: 1242 { 1243 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.presto_edition){ 1244 delimiterchar = ';'; 1245 flexer = new TLexerPresto(); 1246 flexer.delimiterchar = delimiterchar; 1247 flexer.defaultDelimiterStr = defaultDelimiterStr; 1248 fparser = new TParserPresto(null); 1249 fparser.lexer = flexer; 1250 } 1251 break; 1252 } 1253 case dbvtrino: 1254 { 1255 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.trino_edition){ 1256 delimiterchar = ';'; 1257 flexer = new TLexerPresto(); 1258 flexer.delimiterchar = delimiterchar; 1259 flexer.defaultDelimiterStr = defaultDelimiterStr; 1260 fparser = new TParserPresto(null); 1261 fparser.lexer = flexer; 1262 } 1263 break; 1264 } 1265 case dbvdatabricks: 1266 { 1267 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.databricks_edition){ 1268 delimiterchar = ';'; 1269 flexer = new TLexerDatabricks(); 1270 flexer.delimiterchar = delimiterchar; 1271 flexer.defaultDelimiterStr = defaultDelimiterStr; 1272 fparser = new TParserDatabricks(null); 1273 fparser.lexer = flexer; 1274 } 1275 break; 1276 } 1277 case dbvgaussdb: 1278 { 1279 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.gaussdb_edition){ 1280 delimiterchar = ';'; 1281 flexer = new TLexerGaussDB(); 1282 flexer.delimiterchar = delimiterchar; 1283 flexer.defaultDelimiterStr = defaultDelimiterStr; 1284 fparser = new TParserGaussDB(null); 1285 fparser.lexer = flexer; 1286 // fplsqlparser = new TParserOraclePLSql(null); 1287 // fplsqlparser.lexer = new TLexerOracle();// must use oracle lexer, not gauss lexer 1288 } 1289 break; 1290 } 1291 default: { 1292 if (TBaseType.enterprise_edition ||(!TBaseType.full_edition) ||TBaseType.sqlserver_edition){ 1293 flexer = new TLexerMssql(); 1294 flexer.delimiterchar = delimiterchar; 1295 flexer.defaultDelimiterStr = defaultDelimiterStr; 1296 fparser = new TParserMssqlSql(null); 1297 fparser.lexer = flexer; 1298 } 1299 break; 1300 } 1301 } 1302 1303 // For delegated vendors (e.g., MSSQL), fparser may be null here 1304 // It will be set later in doDelegatedRawParse() from vendor parser result 1305 if (fparser != null) { 1306 fparser.getNf().setGsqlParser(this); 1307 } 1308 1309 sourcetokenlist = new TSourceTokenList(); 1310 sourcetokenlist.setGsqlparser(this); 1311 sqlstatements = new TStatementList(); 1312 // Inject vendor-specific command resolver 1313 sqlcmds = SqlCmdsFactory.get(dbVendor); 1314 if (fparser != null) { 1315 fparser.sqlcmds = sqlcmds; 1316 } 1317 sqlpluskeywordList = new HashMap(); 1318 syntaxErrors = new ArrayList(); 1319 //syntaxHints = new ArrayList(); 1320 1321 1322 errormessage = ""; 1323 1324 if (TBaseType.license_expired_check){ 1325 if (!check_license_time()) { 1326 flexer = null; 1327 fparser = null; 1328 // System.out.println("license is expired"); 1329 } 1330 } 1331 1332 TGSqlParser.currentDBVendor = dbVendor; 1333 } 1334 1335 TContext globalContext; 1336 1337 1338 /** 1339 * Create a select statement object from the parameter: subquery 1340 * 1341 * @param subquery a plain text select statement which need to be converted to a {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement} object 1342 * @return a select statement object, return null if the input select string is syntax invalid. 1343 */ 1344 public TSelectSqlStatement parseSubquery(String subquery){ 1345 return parseSubquery(this.dbVendor,subquery); 1346 } 1347 1348 /** 1349 * this method is thread safe. 1350 * 1351 * C:\prg\gsp_java\gsp_java_core\src\test\java\gudusoft\gsqlparser\ParseSubqueryThreadSafetyTest.java 1352 * 1353 */ 1354 public static TSelectSqlStatement parseSubquery(EDbVendor dbVendor, String subquery){ 1355// TGSqlParser localParser = new TGSqlParser(dbVendor); 1356// localParser.sqltext = subquery; 1357// int iRet = localParser.doparse(); 1358// if (iRet != 0) { 1359// return null; 1360// } 1361 1362 TSingletonParser singletonParser = TSingletonParser.getInstance(); 1363 TStatementList statements = singletonParser.getStmts(dbVendor,subquery); 1364 if (statements.size() == 0) return null; 1365 1366 return (TSelectSqlStatement)statements.get(0); 1367 } 1368 1369 /** 1370 * Create an expression object from the parameter: expr 1371 * 1372 * @param expr a plain text expression which will be converted to {@link gudusoft.gsqlparser.nodes.TExpression} object 1373 * @return an expression object, return null if the input expression string is not syntax valid. 1374 */ 1375 public TExpression parseExpression(String expr){ 1376 return parseExpression(this.dbVendor,expr); 1377 } 1378 1379 /* 1380 * this method is thread safe. 1381 * 1382 * getStmts() is synchronized - only one thread can execute it at a time 1383 * getParser() is also synchronized 1384 * Each thread gets a new TStatementList instance 1385 1386 * this is the test case for this method. 1387 * C:\prg\gsp_java\gsp_java_core\src\test\java\gudusoft\gsqlparser\ParseExpressionThreadSafetyTest.java 1388 */ 1389 public static TExpression parseExpression(EDbVendor dbVendor, String expr){ 1390 TSingletonParser singletonParser = TSingletonParser.getInstance(); 1391 1392 boolean e = TBaseType.isEnableResolver(); 1393 TBaseType.setEnableResolver(false); 1394 TStatementList statements; 1395 try{ 1396 statements = singletonParser.getStmts(dbVendor,"select 1 from t where "+TBaseType.newline+expr); 1397 }finally { 1398 TBaseType.setEnableResolver(e); 1399 } 1400 1401 if (statements.size() == 0) return null; 1402 1403// TGSqlParser localParser = new TGSqlParser(dbVendor); 1404// localParser.sqltext = "select 1 from t where "+TBaseType.newline+expr; 1405// int iRet = localParser.doparse(); 1406// if (iRet != 0) { 1407// return null; 1408// } 1409 1410 return ((TSelectSqlStatement)statements.get(0)).getWhereClause().getCondition(); 1411 } 1412 1413 /** 1414 * Create a function object from the parameter: newFunction 1415 * 1416 * @param newFunction a plain text function which will be converted to {@link gudusoft.gsqlparser.nodes.TFunctionCall} object 1417 * @return a function object, or return null if the input string is not a valid function call. 1418 */ 1419 public TFunctionCall parseFunctionCall(String newFunction){ 1420 return parseFunctionCall(this.dbVendor,newFunction); 1421 } 1422 1423 public static TFunctionCall parseFunctionCall(EDbVendor dbVendor, String newFunction){ 1424 TSingletonParser singletonParser = TSingletonParser.getInstance(); 1425 TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newFunction+TBaseType.newline+"from t"); 1426 if (statements.size() == 0) return null; 1427 1428 1429// TGSqlParser localParser = new TGSqlParser(dbVendor); 1430// localParser.sqltext = "select"+TBaseType.newline+newFunction+TBaseType.newline+"from t"; 1431// int iRet = localParser.doparse(); 1432// if (iRet!= 0) { 1433// return null; 1434// } 1435 1436 return statements.get(0).getResultColumnList().getResultColumn(0).getExpr().getFunctionCall(); 1437 } 1438 1439 /** 1440 * Create a database objectName from the parameter: newObjectName 1441 * 1442 * @param newObjectName a plain text objectName which will be converted to {@link gudusoft.gsqlparser.nodes.TObjectName} object 1443 * @return a database objectName object, return null is the input string is not a valid objectName. 1444 */ 1445 public TObjectName parseObjectName(String newObjectName){ 1446 //return parseObjectName(this.dbVendor,newObjectName); 1447 return TObjectName.createObjectName(this.dbVendor,EDbObjectType.column,newObjectName); 1448 } 1449 1450 1451 1452 /** 1453 * 1454 * @param dbVendor 1455 * @param newObjectName 1456 * @return 1457 */ 1458 public static TObjectName parseObjectName(EDbVendor dbVendor, String newObjectName){ 1459 1460 TSingletonParser singletonParser = TSingletonParser.getInstance(); 1461 TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newObjectName+TBaseType.newline+"from t"); 1462 if (statements.size() == 0) return null; 1463 TExpression e = statements.get(0).getResultColumnList().getResultColumn(0).getExpr(); 1464 1465// TGSqlParser localParser = new TGSqlParser(dbVendor); 1466// localParser.sqltext = "select"+TBaseType.newline+newObjectName+TBaseType.newline+"from t"; 1467// int iRet = localParser.doparse(); 1468// if (iRet!= 0) { 1469// return null; 1470// } 1471// TExpression e = ((TSelectSqlStatement)localParser.sqlstatements.get(0)).getResultColumnList().getResultColumn(0).getExpr(); 1472 1473 TObjectName lcResult = null; 1474 switch (e.getExpressionType()){ 1475 case simple_object_name_t: 1476 lcResult = e.getObjectOperand(); 1477 break; 1478 case simple_constant_t: 1479 lcResult = new TObjectName(); 1480 lcResult.init(e.getConstantOperand().getValueToken()); 1481 break; 1482 default: 1483 break; 1484 } 1485 1486 return lcResult; 1487 } 1488 1489 /** 1490 * Create an constant object from the parameter: newConstant 1491 * 1492 * @param newConstant a plian text constant which will be converted to {@link gudusoft.gsqlparser.nodes.TConstant} object 1493 * @return new constant object, returns null if the input is not a valid constant string. 1494 */ 1495 public TConstant parseConstant(String newConstant){ 1496 return parseConstant(this.dbVendor,newConstant); 1497 } 1498 1499 public static TConstant parseConstant(EDbVendor dbVendor, String newConstant){ 1500// TGSqlParser localParser = new TGSqlParser(dbVendor); 1501// localParser.sqltext = "select"+TBaseType.newline+newConstant+TBaseType.newline+"from t"; 1502// int iRet = localParser.doparse(); 1503// if (iRet!= 0) { 1504// return null; 1505// } 1506 1507 TSingletonParser singletonParser = TSingletonParser.getInstance(); 1508 TStatementList statements = singletonParser.getStmts(dbVendor,"select"+TBaseType.newline+newConstant+TBaseType.newline+"from t"); 1509 if (statements.size() == 0) return null; 1510 1511 return statements.get(0).getResultColumnList().getResultColumn(0).getExpr().getConstantOperand(); 1512 } 1513 1514 1515 /** 1516 * The total number of syntax errors founded in the input SQL script. 1517 * <br>Only the first syntax error in a SQL statement is counted if there are more than one syntax errors in 1518 * a single SQL statement. 1519 * <br> In a SQL script, only the first syntax error in each SQL statement is counted. 1520 * 1521 * @return The total number of syntax errors founded in the input SQL script. Returns 0 if no syntax error is founded. 1522 */ 1523 public int getErrorCount(){ 1524 return syntaxErrors.size(); 1525 } 1526 1527 /** 1528 * The text of error message generated by iterating all items in {@link #getSyntaxErrors}. 1529 * User may generate error message in their own format by iterating all items in {@link #getSyntaxErrors}. 1530 * 1531 * @return error message 1532 */ 1533 public String getErrormessage(){ 1534 1535 String s="",hint="Syntax error"; 1536 TSyntaxError t; 1537 for (int i= 0; i< syntaxErrors.size(); i++) 1538 { 1539 t = (TSyntaxError) syntaxErrors.get(i); 1540 if (t.hint.length() > 0) hint = t.hint; 1541 s= s+hint+"("+t.errorno+") near: "+t.tokentext; 1542 s=s+"("+t.lineNo; 1543 s=s+","+t.columnNo +", token code:"+t.tokencode+")"; 1544 //s=s+" expected tokentext:"+t.hint; 1545 1546 // break;//get only one message, remove this one and uncomment next line to get all error messages 1547 if (i != syntaxErrors.size() - 1) 1548 s = s +TBaseType.linebreak; 1549 } 1550 1551 if (errormessage.length() > 0){ 1552 s = errormessage+TBaseType.linebreak+s; 1553 } 1554 return s; 1555 1556 } 1557 1558 /** 1559 * check syntax of the input SQL. This method works exactly the same as {@link #parse} method. 1560 * 1561 * @return 0 means parse SQL script successfully, otherwise, use {@link #getErrorCount}, {@link #getErrormessage} 1562 * to get detailed error information. 1563 * @see #parse 1564 */ 1565 public int checkSyntax(){ 1566 return doparse(); 1567 } 1568 1569 /** 1570 * Check syntax of the input SQL, doing some kind of semantic analysis without connecting to a real database. 1571 * <p></p> 1572 * This method will do a in-depth analysis of the input SQL such as building the link between table and columns. 1573 * The parse tree of the input SQL is available after calling this method. 1574 * 1575 * The parser checks the syntax of those SQL statements one by one. If syntax error is found in a SQL statement, 1576 * an error will be logged, no parse tree will be built for this SQL statement, 1577 * the error message can be fetched using the {@link #getErrormessage()} method. 1578 * <p></p> 1579 * The syntax error in one SQL statement doesn't prevent the parser continue to check the syntax of the next SQL statement. 1580 * After checking syntax of all SQL statements, use the {@link #getErrorCount()} method to get the total number of errors. 1581 * <p></p> 1582 * A syntax error in a SQL stored procedure will cease this parser to check syntax of the rest SQL statements 1583 * in this stored procedure. 1584 * 1585 * @return 0 means parse SQL script successfully, otherwise, use {@link #getErrorCount}, {@link #getErrormessage} 1586 * to get detailed error information. 1587 * @see #getSyntaxErrors 1588 */ 1589 1590 public int parse(){ 1591 return doparse(); 1592 } 1593 1594 public int validate(){ 1595 if (sqlstatements.size() == 0) return 0; 1596 1597 TRelationValidator relationValidate = new TRelationValidator(globalContext); 1598 for(TCustomSqlStatement sqlStatement:sqlstatements){ 1599 sqlStatement.acceptChildren(relationValidate); 1600 } 1601 return 0; 1602 } 1603 1604 void setdelimiterchar(char ch){ 1605 delimiterchar = ch; 1606 flexer.delimiterchar = ch; 1607 } 1608 char curdelimiterchar; 1609 String userDelimiterStr =""; 1610 1611 boolean includesqlstatementtype(ESqlStatementType search, ESqlStatementType[] src){ 1612 boolean ret = false; 1613 for(int i=0;i<src.length;i++){ 1614 if (src[i] == search){ 1615 ret = true; 1616 break; 1617 } 1618 } 1619 return ret; 1620 } 1621 1622 // private int getfileEncodingType(FileInputStream inputStream){ 1623 // BufferedInputStream fr = new BufferedInputStream(inputStream,8); 1624 // return getfileEncodingType(fr); 1625 // } 1626 1627 private int getfileEncodingType(BufferedInputStream fr){ 1628 int ret = 0; // default, 1: utf-16, 2: utf-32 1629 // BufferedInputStream fr = new BufferedInputStream(inputStream,8); 1630 try { 1631 byte[] bom = new byte[4]; 1632 fr.mark(bom.length+1); 1633 1634 fr.read(bom,0,bom.length); 1635 if ( ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE)) 1636 ||((bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF)) 1637 ) 1638 { 1639 ret = 1; 1640 if ( ((bom[2] == (byte)0xFF) && (bom[3] == (byte)0xFE)) 1641 ||((bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF)) 1642 ){ 1643 ret = 2; 1644 } 1645 }else{ 1646 if ((bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB)&& (bom[2] == (byte)0xBF)){ 1647 ret = 3; //UTF-8,EF BB BF 1648 } 1649 } 1650 fr.reset(); 1651 } catch (FileNotFoundException e) { 1652 // e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1653 } catch (IOException e) { 1654 //e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1655 } 1656 return ret; 1657 } 1658 1659 // private int getfileEncodingType(String fn){ 1660 // int ret = 0; // default, 1: utf-16, 2: utf-32 1661 // try { 1662 // FileInputStream fr = new FileInputStream(fn); 1663 // ret = getfileEncodingType(fr); 1664 // fr.close(); 1665 1666 // } catch (FileNotFoundException e) { 1667 // // e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1668 // } catch (IOException e) { 1669 // //e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1670 // } 1671 // return ret; 1672 // } 1673 1674 int readsql(){ 1675 int ret = 0; 1676 1677 syntaxErrors.clear(); 1678 //syntaxHints.clear(); 1679 1680 if (((!TBaseType.full_edition))||(!TBaseType.need_license_file)){ 1681 if (!TBaseType.need_license_file){ 1682 licenseType = TBaseType.license_type_dist; 1683 userName = "dist"; 1684 }else { 1685 licenseType = TBaseType.license_type_trial; 1686 userName = TBaseType.license_trail_username; 1687 } 1688 // machineId = new HardwareBinder().getMachineIdString(); 1689 }else { 1690 if (!licenseOK){ 1691 errormessage = licenseMessage; 1692 return -1; 1693 } 1694 } 1695 1696 try{ 1697 if (finputstream != null) finputstream.close(); 1698 if (flexer == null){ 1699 ret = -1; 1700 errormessage = "requested database not supported:"+this.dbVendor.toString(); 1701 return ret; 1702 } 1703 if (flexer.yyinput != null) flexer.yyinput.close(); 1704 1705 }catch(IOException e){ 1706 ret = -1; 1707 errormessage = "requested database not supported"; 1708 } 1709 1710 if (sqltext.length() > 0){ 1711 finputstream = new BufferedReader(new StringReader(sqltext), TBaseType.LEXER_INPUT_BUFFER_SIZE); 1712 if ((!TBaseType.full_edition) && (sqltext.length() > TBaseType.query_size_limitation)){ 1713 errormessage = TBaseType.trail_version_query_message; 1714 ret = -1; 1715 } 1716 }else if (sqlfilename.length() > 0){ 1717 try{ 1718 1719 streamFromSqlFile = new FileInputStream(sqlfilename); 1720 // Buffer it for mark/reset support 1721 BufferedInputStream bufferedStream = new BufferedInputStream(streamFromSqlFile,8); 1722 int encodingtype = getfileEncodingType(bufferedStream); 1723 streamFromSqlFile.getChannel().position(0); 1724 1725 if(encodingtype == 1){ 1726 sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-16"); 1727 }else if(encodingtype == 2){ 1728 sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-32"); 1729 }else if(encodingtype == 3){ 1730 // System.out.println("utf-8"); 1731 sqlStreamReader = new InputStreamReader(streamFromSqlFile,"UTF-8"); 1732 } 1733 else{ 1734 if (sqlCharset == null){ 1735 sqlCharset = Charset.defaultCharset().name(); 1736 //System.out.println("Charset used: "+Charset.defaultCharset().name()); 1737 } 1738 sqlStreamReader = new InputStreamReader(streamFromSqlFile, sqlCharset); 1739 // isr = new InputStreamReader(fr,"Cp737"); 1740 } 1741 1742 finputstream = new BufferedReader(sqlStreamReader, TBaseType.LEXER_INPUT_BUFFER_SIZE); 1743 if (encodingtype == 3){ 1744 //EF BB BF was not stripped by the InputStreamReader, so we do it 1745 finputstream.skip(1); 1746 } 1747 1748 if ((!TBaseType.full_edition)){ 1749 File file = new File(sqlfilename); 1750 if (!file.exists() || !file.isFile()) { 1751 ret = -1; 1752 errormessage = "not a valid sql file."; 1753 }else{ 1754 if (file.length() > TBaseType.query_size_limitation){ 1755 errormessage = TBaseType.trail_version_file_message; 1756 ret = -1; 1757 } 1758 } 1759 } 1760 1761 }catch(FileNotFoundException e){ 1762 ret = -1; 1763 errormessage = e.toString(); 1764 } catch (UnsupportedEncodingException e) { 1765 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1766 } catch (IOException e) { 1767 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1768 } 1769 1770 }else if(this.sqlInputStream != null){ 1771 int encodingtype = getfileEncodingType(sqlInputStream); 1772 InputStream fr = sqlInputStream; 1773 1774 InputStreamReader isr = null; 1775 try{ 1776 1777 if(encodingtype == 1){ 1778 isr = new InputStreamReader(fr,"UTF-16"); 1779 }else if(encodingtype == 2){ 1780 isr = new InputStreamReader(fr,"UTF-32"); 1781 }else if(encodingtype == 3){ 1782 // System.out.println("utf-8"); 1783 isr = new InputStreamReader(fr,"UTF-8"); 1784 } 1785 else{ 1786 if (sqlCharset == null){ 1787 sqlCharset = Charset.defaultCharset().name(); 1788 } 1789 1790 isr = new InputStreamReader(fr, sqlCharset); 1791 } 1792 1793 finputstream = new BufferedReader(isr, TBaseType.LEXER_INPUT_BUFFER_SIZE); 1794 if (encodingtype == 3){ 1795 //EF BB BF was not stripped by the InputStreamReader, so we do it 1796 finputstream.skip(1); 1797 } 1798 1799 }catch(FileNotFoundException e){ 1800 ret = -1; 1801 errormessage = e.toString(); 1802 } catch (UnsupportedEncodingException e) { 1803 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1804 } catch (IOException e) { 1805 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1806 } 1807 1808 try { 1809 if ((!TBaseType.full_edition) && (sqlInputStream.available() > TBaseType.query_size_limitation)){ 1810 errormessage = TBaseType.trail_version_query_message; 1811 ret = -1; 1812 } 1813 } catch (IOException e) { 1814 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 1815 } 1816 } 1817 1818 if (finputstream == null) ret = -1; 1819 1820 if (ret == 0) 1821 { 1822 flexer.yyinput = finputstream; 1823 flexer.setSqlCharset(this.sqlCharset); 1824 flexer.reset(); 1825 } 1826 1827 sourcetokenlist.clear(); 1828 sourcetokenlist.curpos = -1; 1829 1830 flexer.resetTokenTable(); 1831 1832 1833 return ret; 1834 } 1835 1836 TSourceToken getanewsourcetoken(){ 1837 TSourceToken pst = null,prevst; 1838 1839 while (true) { 1840 pst = new TSourceToken(""); 1841 if (flexer.yylexwrap(pst) == 0) { pst = null; break;} 1842 1843 pst.setDbvendor(dbVendor); 1844 pst.tokenstatus = ETokenStatus.tsoriginal; 1845 if (pst.tokentype == ETokenType.ttreturn){ 1846 pst.setAstext(towinlinebreak(pst.getAstext())); 1847 } 1848 //combine space && linebreak after a linebreak into one 1849 if ( (pst.tokentype == ETokenType.ttwhitespace) 1850 && (sourcetokenlist.curpos >= 0) ) 1851 { 1852 prevst = sourcetokenlist.get(sourcetokenlist.curpos); 1853 if ( prevst.tokentype == ETokenType.ttreturn ) 1854 { 1855 //can't discard whitespace after linebreak, it will be used 1856 // to judge whether / at the { of the line is a sqlplus cmd or not 1857 // check isvalidplacefordivtosqlpluscmd for more 1858 prevst.setAstext(prevst.getAstext() + pst.getAstext()); 1859 //newst.free; 1860 //newst = nil; 1861 continue; 1862 } 1863 } 1864 1865 if ( (pst.tokentype == ETokenType.ttreturn) 1866 && (sourcetokenlist.curpos >= 0) ) 1867 { 1868 prevst = sourcetokenlist.get(sourcetokenlist.curpos); 1869 1870 if ( prevst.tokentype == ETokenType.ttreturn ) 1871 { 1872 prevst.setAstext(prevst.getAstext() + pst.getAstext()); 1873 //newst.free; 1874 //newst = nil; 1875 continue; 1876 } 1877 1878 if ( prevst.tokentype == ETokenType.ttwhitespace ) 1879 { 1880 //merge previous whitespace with this linebreak 1881 //doesn't work for sqlplus cmd 1882 1883 // prevst.sourcecode = newst.sourcecode; 1884 // prevst.tokentype = newst.tokentype; 1885 // prevst.tokencode = newst.tokencode; 1886 // newst.free; 1887 // newst = nil; 1888 // continue; 1889 1890 //prevst.prevsourcecode = prevst.astext; 1891 //prevst.astext = ""; 1892 } 1893 } 1894 1895 break; 1896 1897 } 1898 1899 if (pst != null){ 1900 pst.container = sourcetokenlist; 1901 sourcetokenlist.curpos = sourcetokenlist.curpos+1; 1902 pst.posinlist = sourcetokenlist.curpos; 1903 if (tokenHandle != null){ 1904 tokenHandle.processToken(pst); 1905 } 1906 } 1907 1908 // System.out.println(pst); 1909 // flexer.setTokenTableValue(pst); 1910 return pst; 1911 1912 } 1913 1914 String towinlinebreak(String s){ 1915 return s; 1916// todo not implemented yet 1917 } 1918 1919void checkconstarinttoken(TSourceToken lcprevtoken){ 1920 TSourceTokenList lcStList = lcprevtoken.container; 1921 if (TBaseType.assigned(lcStList)) 1922 { 1923 TSourceToken lcPPToken = lcStList.nextsolidtoken(lcprevtoken.posinlist,-2,false); 1924 if (TBaseType.assigned(lcPPToken)) 1925 { 1926 1927 if (lcPPToken.tokencode == flexer.getkeywordvalue("constraint")) 1928 { 1929 //System.out.println(lcPPToken); 1930 lcPPToken.tokencode = TBaseType.rw_constraint2; 1931 } 1932 } 1933 } 1934 1935} 1936 1937TSourceToken getprevtoken(TSourceToken ptoken){ 1938 // ETokenType[] lcnonsolidtokenset = {ETokenType.ttwhitespace,ETokenType.ttreturn,ETokenType.ttsimplecomment,ETokenType.ttbracketedcomment} ; 1939 TSourceTokenList lcstlist = ptoken.container; 1940 if (TBaseType.assigned(lcstlist)){ 1941 if ((ptoken.posinlist > 0) && (lcstlist.size() > ptoken.posinlist-1)) 1942 { 1943 if (!( 1944 (lcstlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttwhitespace) 1945 ||(lcstlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttreturn) 1946 ||(lcstlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttsimplecomment) 1947 ||(lcstlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttbracketedcomment) 1948 ) 1949 ) 1950 {return lcstlist.get(ptoken.posinlist-1);} 1951 else{ 1952 { return lcstlist.nextsolidtoken(ptoken.posinlist-1,-1,false);} 1953 } 1954 } 1955 } 1956 1957 return null; 1958} 1959 1960void doinformixtexttotokenlist(){ 1961 TSourceToken lcprevtoken = null; 1962 int lcsteps = 0; 1963 TSourceToken asourcetoken,lctoken, lctoken2,lctoken3; 1964 int yychar; 1965 boolean iskeywordgo; 1966 1967 asourcetoken = getanewsourcetoken(); 1968 1969 if ( asourcetoken == null ) return; 1970 1971 yychar = asourcetoken.tokencode; 1972 1973 1974 boolean lcinopenrowset = false; 1975 int lcnested = 0; 1976 1977 while (yychar > 0) 1978 { 1979 1980 if ( asourcetoken.tokencode == TBaseType.rrw_openrowset ) 1981 { 1982 // openrowset(....) 1983 lcinopenrowset = true; 1984 lcnested = 0; 1985 } 1986 else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis) 1987 { 1988 if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken)) 1989 { 1990 if ( lcprevtoken.tokencode == TBaseType.rrw_primary ) 1991 { 1992 lcprevtoken.tokencode = TBaseType.rrw_select - 2; //rw_primary2 1993 //checkconstarinttoken(lcprevtoken); 1994 } 1995 else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign ) 1996 { 1997 lcprevtoken.tokencode = TBaseType.rrw_select - 4; //rw_foreign2 1998 //checkconstarinttoken(lcprevtoken); 1999 } 2000 else if ( lcprevtoken.tokencode == TBaseType.rrw_unique ) 2001 { 2002 lcprevtoken.tokencode = TBaseType.rrw_select - 1; //rw_unique2 2003 // checkconstarinttoken(lcprevtoken); 2004 } 2005 else if ( lcprevtoken.tokencode == TBaseType.rrw_distinct ) 2006 { 2007 lcprevtoken.tokencode = TBaseType.rrw_select - 6; //rw_distinct2 2008 //checkconstarinttoken(lcprevtoken); 2009 } 2010 lcprevtoken = null; 2011 lcsteps = 0; 2012 } 2013 2014 // openrowset(....) 2015 if ( lcinopenrowset ) 2016 lcnested++; 2017 } 2018 else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis) 2019 { 2020 // openrowset(....) 2021 if ( lcinopenrowset ) 2022 { 2023 if ( (lcnested > 0) ) 2024 lcnested--; 2025 if ( lcnested == 0 ) 2026 lcinopenrowset = false; 2027 } 2028 } 2029 else if ( asourcetoken.tokentype == ETokenType.ttsemicolon ) 2030 { 2031 if ( lcinopenrowset ){ 2032 asourcetoken.tokentype = ETokenType.ttsemicolon2; 2033 }else{ 2034 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1); 2035 if (lctoken2 != null){ 2036 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2037 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2038 }else{ 2039 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1); 2040 if (lctoken2 == null){ 2041 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1); 2042 } 2043 if (lctoken2 != null){ 2044 lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2); 2045 if (lctoken3 != null){ 2046 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2047 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2048 } 2049 } 2050 } 2051 } 2052 } 2053 else if ( asourcetoken.tokentype == ETokenType.ttperiod) 2054 { 2055 lctoken = getprevtoken(asourcetoken); 2056 // System.out.println(lctoken); 2057 if ( TBaseType.assigned(lctoken) ) 2058 { // go.fieldname, go is a table alias, not a go statement 2059 if ( lctoken.tokencode == TBaseType.rrw_go ) 2060 { 2061 lctoken.tokencode = TBaseType.ident; 2062 lctoken.tokentype = ETokenType.ttidentifier; 2063 } 2064 } 2065 } 2066 else if ( asourcetoken.tokencode == TBaseType.rrw_table ){ 2067 lctoken = getprevtoken(asourcetoken); 2068 if (TBaseType.assigned(lctoken)) 2069 { 2070 if (lctoken.tokencode == TBaseType.rrw_lock ) 2071 { 2072 lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable 2073 } 2074 } 2075 } 2076 else if ( asourcetoken.tokencode == TBaseType.rrw_to ){ 2077 lctoken = getprevtoken(asourcetoken); 2078 if (TBaseType.assigned(lctoken)) 2079 { 2080 if (lctoken.tokencode == TBaseType.rrw_connect ) 2081 { 2082 lctoken.tokencode = TBaseType.rrw_informix_connect_to;//connect to statement 2083 } 2084 } 2085 } 2086 else if ( asourcetoken.tokencode == TBaseType.rrw_go ) 2087 { 2088 iskeywordgo = true; 2089 lctoken = getprevtoken(asourcetoken); 2090 if ( TBaseType.assigned(lctoken) ) 2091 { // go should not at same line as other sql statement 2092 if ( lctoken.lineNo == asourcetoken.lineNo) 2093 { 2094 iskeywordgo = false; 2095 } 2096 } 2097 2098 if ( iskeywordgo ) 2099 { 2100 lcinopenrowset = false; 2101 lcnested = 0; 2102 lcprevtoken = asourcetoken; 2103 } 2104 else 2105 { 2106 // System.out.println(asourcetoken); 2107 asourcetoken.tokencode = TBaseType.ident; 2108 asourcetoken.tokentype = ETokenType.ttidentifier; 2109 } 2110 } 2111 else if ( asourcetoken.tokencode == TBaseType.rrw_primary ) 2112 { 2113 // primary key [clustered | nonclustered ] ( column list) 2114 lcsteps = 2; 2115 lcprevtoken = asourcetoken; 2116 } 2117 else if ( asourcetoken.tokencode == TBaseType.rrw_foreign ) 2118 { 2119 // foreign key [clustered | nonclustered ] ( column list) 2120 lcsteps = 2; 2121 lcprevtoken = asourcetoken; 2122 } 2123 else if ( asourcetoken.tokencode == TBaseType.rrw_unique ) 2124 { 2125 // unique [clustered | nonclustered ] ( column list) 2126 lcsteps = 1; 2127 lcprevtoken = asourcetoken; 2128 } 2129 else if ( asourcetoken.issolidtoken() ) 2130 { 2131 if ( lcsteps > 0 ) 2132 { 2133 if ( !(TBaseType.mysametext("clustered",asourcetoken.toString()) 2134 || TBaseType.mysametext("nonclustered",asourcetoken.toString())) ) 2135 lcsteps--; 2136 } 2137 } 2138 2139 //System.out.println(asourcetoken); 2140 sourcetokenlist.add(asourcetoken); 2141 2142 2143 //flexer.yylexwrap(asourcetoken); 2144 asourcetoken = getanewsourcetoken(); 2145 if (asourcetoken != null){ 2146 yychar = asourcetoken.tokencode; 2147 }else{ 2148 yychar = 0; 2149 } 2150 2151 } 2152 2153 } 2154 2155 void domssqlsqltexttotokenlist(){ 2156 TSourceToken lcprevtoken = null; 2157 int lcsteps = 0; 2158 TSourceToken asourcetoken,lctoken, lctoken2,lctoken3; 2159 int yychar; 2160 boolean iskeywordgo; 2161 2162 asourcetoken = getanewsourcetoken(); 2163 2164 if ( asourcetoken == null ) return; 2165 2166 yychar = asourcetoken.tokencode; 2167 2168 2169 boolean lcinopenrowset = false; 2170 int lcnested = 0; 2171 2172 while (yychar > 0) 2173 { 2174 2175 if ( asourcetoken.tokencode == TBaseType.rrw_openrowset ) 2176 { 2177 // openrowset(....) 2178 lcinopenrowset = true; 2179 lcnested = 0; 2180 } 2181 else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis) 2182 { 2183 if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken)) 2184 { 2185 if ( lcprevtoken.tokencode == TBaseType.rrw_primary ) 2186 { 2187 lcprevtoken.tokencode = TBaseType.rrw_select - 2; //rw_primary2 2188 checkconstarinttoken(lcprevtoken); 2189 } 2190 else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign ) 2191 { 2192 lcprevtoken.tokencode = TBaseType.rrw_select - 4; //rw_foreign2 2193 checkconstarinttoken(lcprevtoken); 2194 } 2195 else if ( lcprevtoken.tokencode == TBaseType.rrw_unique ) 2196 { 2197 lcprevtoken.tokencode = TBaseType.rrw_select - 1; //rw_unique2 2198 checkconstarinttoken(lcprevtoken); 2199 } 2200 lcprevtoken = null; 2201 lcsteps = 0; 2202 } 2203 2204 // openrowset(....) 2205 if ( lcinopenrowset ) 2206 lcnested++; 2207 } 2208 else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis) 2209 { 2210 // openrowset(....) 2211 if ( lcinopenrowset ) 2212 { 2213 if ( (lcnested > 0) ) 2214 lcnested--; 2215 if ( lcnested == 0 ) 2216 lcinopenrowset = false; 2217 } 2218 } 2219 else if ( asourcetoken.tokentype == ETokenType.ttsemicolon ) 2220 { 2221 if ( lcinopenrowset ){ 2222 asourcetoken.tokentype = ETokenType.ttsemicolon2; 2223 }else{ 2224 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1); 2225 if (lctoken2 != null){ 2226 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2227 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2228 }else{ 2229 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1); 2230 if (lctoken2 == null){ 2231 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1); 2232 } 2233 if (lctoken2 != null){ 2234 lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2); 2235 if (lctoken3 != null){ 2236 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2237 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2238 } 2239 } 2240 } 2241 } 2242 2243 lctoken = getprevtoken(asourcetoken); 2244 if ((lctoken != null)){ 2245 if (lctoken.tokentype == ETokenType.ttsemicolon){ 2246 // treat this semicolon as a whitespace 2247 asourcetoken.tokencode = TBaseType.lexspace; 2248 } 2249 } 2250 } 2251 else if ( asourcetoken.tokentype == ETokenType.ttperiod) 2252 { 2253 lctoken = getprevtoken(asourcetoken); 2254 // System.out.println(lctoken); 2255 if ( TBaseType.assigned(lctoken) ) 2256 { // go.fieldname, go is a table alias, not a go statement 2257 if ( lctoken.tokencode == TBaseType.rrw_go ) 2258 { 2259 lctoken.tokencode = TBaseType.ident; 2260 lctoken.tokentype = ETokenType.ttidentifier; 2261 } 2262 } 2263 } 2264 else if ( asourcetoken.tokencode == TBaseType.rrw_table ){ 2265 lctoken = getprevtoken(asourcetoken); 2266 if (TBaseType.assigned(lctoken)) 2267 { 2268 if (lctoken.tokencode == TBaseType.rrw_lock ) 2269 { 2270 lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable 2271 } 2272 } 2273 } 2274 else if ( asourcetoken.tokencode == TBaseType.rrw_into ){ 2275 lctoken = getprevtoken(asourcetoken); 2276 if (TBaseType.assigned(lctoken)) 2277 { 2278 if (lctoken.tokencode == TBaseType.rrw_sqlserver_copy ) 2279 { 2280 lctoken.tokencode = TBaseType.rrw_sqlserver_copyinto; 2281 } 2282 } 2283 } 2284 else if ( asourcetoken.tokencode == TBaseType.rrw_sqlserver_column ){ 2285 lctoken = getprevtoken(asourcetoken); 2286 if (TBaseType.assigned(lctoken)) 2287 { 2288 if (lctoken.tokencode == TBaseType.rrw_drop ) 2289 { 2290 asourcetoken.tokencode = TBaseType.rrw_sqlserver_drop_column; 2291 } 2292 } 2293 } 2294 else if ( asourcetoken.tokencode == TBaseType.rrw_go ) 2295 { 2296 iskeywordgo = true; 2297 lctoken = getprevtoken(asourcetoken); 2298 if ( TBaseType.assigned(lctoken) ) 2299 { // go should not at same line as other sql statement 2300 if (( lctoken.lineNo == asourcetoken.lineNo)&&(lctoken.tokencode != ';')) 2301 { 2302 iskeywordgo = false; 2303 } 2304 } 2305 2306 if ( iskeywordgo ) 2307 { 2308 lcinopenrowset = false; 2309 lcnested = 0; 2310 lcprevtoken = asourcetoken; 2311 } 2312 else 2313 { 2314 // System.out.println(asourcetoken); 2315 asourcetoken.tokencode = TBaseType.ident; 2316 asourcetoken.tokentype = ETokenType.ttidentifier; 2317 } 2318 } 2319 else if ( asourcetoken.tokencode == TBaseType.rrw_primary ) 2320 { 2321 // primary key [clustered | nonclustered ] [hash] ( column list) 2322 lcsteps = 2; 2323 lcprevtoken = asourcetoken; 2324 } 2325 else if ( asourcetoken.tokencode == TBaseType.rrw_foreign ) 2326 { 2327 // foreign key [clustered | nonclustered ] ( column list) 2328 lcsteps = 2; 2329 lcprevtoken = asourcetoken; 2330 } 2331 else if ( asourcetoken.tokencode == TBaseType.rrw_unique ) 2332 { 2333 // unique [clustered | nonclustered ] [hash] ( column list) 2334 lcsteps = 1; 2335 lcprevtoken = asourcetoken; 2336 } 2337 else if ( asourcetoken.issolidtoken() ) 2338 { 2339 if ( lcsteps > 0 ) 2340 { 2341 if ( !(TBaseType.mysametext("clustered",asourcetoken.toString()) 2342 || TBaseType.mysametext("nonclustered",asourcetoken.toString()) 2343 || TBaseType.mysametext("hash",asourcetoken.toString()) 2344 ) ) 2345 lcsteps--; 2346 } 2347 } 2348 2349 //System.out.println(asourcetoken); 2350 sourcetokenlist.add(asourcetoken); 2351 2352 2353 //flexer.yylexwrap(asourcetoken); 2354 asourcetoken = getanewsourcetoken(); 2355 if (asourcetoken != null){ 2356 yychar = asourcetoken.tokencode; 2357 }else{ 2358 yychar = 0; 2359 } 2360 2361 } 2362 2363 } 2364 2365 void dosybasesqltexttotokenlist(){ 2366 TSourceToken lcprevtoken = null; 2367 int lcsteps = 0; 2368 TSourceToken asourcetoken,lctoken, lctoken2,lctoken3; 2369 int yychar; 2370 boolean iskeywordgo; 2371 2372 2373 asourcetoken = getanewsourcetoken(); 2374 2375 if ( asourcetoken == null ) return; 2376 2377 yychar = asourcetoken.tokencode; 2378 2379 2380 boolean lcinopenrowset = false; 2381 int lcnested = 0; 2382 2383 while (yychar > 0) 2384 { 2385 2386 if ( asourcetoken.tokencode == TBaseType.rrw_openrowset ) 2387 { 2388 // openrowset(....) 2389 lcinopenrowset = true; 2390 lcnested = 0; 2391 } 2392 else if ( asourcetoken.tokentype == ETokenType.ttleftparenthesis) 2393 { 2394 if ( (lcsteps > 0) && TBaseType.assigned(lcprevtoken)) 2395 { 2396 if ( lcprevtoken.tokencode == TBaseType.rrw_primary ) 2397 { 2398 lcprevtoken.tokencode = TBaseType.rrw_select - 2; //rw_primary2 2399 checkconstarinttoken(lcprevtoken); 2400 } 2401 else if ( lcprevtoken.tokencode == TBaseType.rrw_foreign ) 2402 { 2403 lcprevtoken.tokencode = TBaseType.rrw_select - 4; //rw_foreign2 2404 checkconstarinttoken(lcprevtoken); 2405 } 2406 else if ( lcprevtoken.tokencode == TBaseType.rrw_unique ) 2407 { 2408 lcprevtoken.tokencode = TBaseType.rrw_select - 1; //rw_unique2 2409 checkconstarinttoken(lcprevtoken); 2410 } 2411 lcprevtoken = null; 2412 lcsteps = 0; 2413 } 2414 2415 // openrowset(....) 2416 if ( lcinopenrowset ) 2417 lcnested++; 2418 } 2419 else if ( asourcetoken.tokentype == ETokenType.ttrightparenthesis) 2420 { 2421 // openrowset(....) 2422 if ( lcinopenrowset ) 2423 { 2424 if ( (lcnested > 0) ) 2425 lcnested--; 2426 if ( lcnested == 0 ) 2427 lcinopenrowset = false; 2428 } 2429 } 2430 else if ( asourcetoken.tokentype == ETokenType.ttsemicolon ) 2431 { 2432 if ( lcinopenrowset ){ 2433 asourcetoken.tokentype = ETokenType.ttsemicolon2; 2434 }else{ 2435 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_begin,-1); 2436 if (lctoken2 != null){ 2437 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2438 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2439 }else{ 2440 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_try,-1); 2441 if (lctoken2 == null){ 2442 lctoken2 = asourcetoken.searchToken(TBaseType.rrw_catch,-1); 2443 } 2444 if (lctoken2 != null){ 2445 lctoken3 = asourcetoken.searchToken(TBaseType.rrw_begin,-2); 2446 if (lctoken3 != null){ 2447 asourcetoken.tokencode = TBaseType.SEMI_COLON_AFTER_BEGIN; 2448 asourcetoken.tokentype = ETokenType.ttsemicolon3; 2449 } 2450 } 2451 } 2452 } 2453 } 2454 else if ( asourcetoken.tokentype == ETokenType.ttperiod) 2455 { 2456 lctoken = getprevtoken(asourcetoken); 2457 // System.out.println(lctoken); 2458 if ( TBaseType.assigned(lctoken) ) 2459 { // go.fieldname, go is a table alias, not a go statement 2460 if ( lctoken.tokencode == TBaseType.rrw_go ) 2461 { 2462 lctoken.tokencode = TBaseType.ident; 2463 lctoken.tokentype = ETokenType.ttidentifier; 2464 } 2465 } 2466 } 2467 else if ( asourcetoken.tokencode == TBaseType.rrw_table ){ 2468 lctoken = getprevtoken(asourcetoken); 2469 if (TBaseType.assigned(lctoken)) 2470 { 2471 if (lctoken.tokencode == TBaseType.rrw_lock ) 2472 { 2473 lctoken.tokencode = TBaseType.rw_locktable; //TBaseType.rw_locktable 2474 } 2475 } 2476 } 2477 else if ( asourcetoken.tokencode == TBaseType.rrw_sybase_isolation ){ 2478 lctoken = getprevtoken(asourcetoken); 2479 if (TBaseType.assigned(lctoken)) 2480 { 2481 if (lctoken.tokencode == TBaseType.rrw_sybase_at ) 2482 { 2483 lctoken.tokencode = TBaseType.rw_sybase_at1; //TBaseType.rw_locktable 2484 } 2485 } 2486 } 2487 else if ( asourcetoken.tokencode == TBaseType.rrw_update ){ 2488 lctoken = getprevtoken(asourcetoken); 2489 if (TBaseType.assigned(lctoken)) 2490 { 2491 if ((lctoken.tokencode == TBaseType.rrw_not ) 2492 ||(lctoken.tokencode == TBaseType.rrw_and ) 2493 ||(lctoken.tokencode == TBaseType.rrw_or ) 2494 ||(lctoken.tokencode == TBaseType.rrw_if ) 2495 ) 2496 { 2497 // this is update(column) in create trigger 2498 asourcetoken.tokencode = TBaseType.rw_sybase_update1; 2499 } 2500 } 2501 } 2502 else if ( asourcetoken.tokencode == TBaseType.rrw_go ) 2503 { 2504 iskeywordgo = true; 2505 lctoken = getprevtoken(asourcetoken); 2506 if ( TBaseType.assigned(lctoken) ) 2507 { // go should not at same line as other sql statement 2508 if ( lctoken.lineNo == asourcetoken.lineNo) 2509 { 2510 iskeywordgo = false; 2511 } 2512 } 2513 2514 if ( iskeywordgo ) 2515 { 2516 lcinopenrowset = false; 2517 lcnested = 0; 2518 lcprevtoken = asourcetoken; 2519 } 2520 else 2521 { 2522 // System.out.println(asourcetoken); 2523 asourcetoken.tokencode = TBaseType.ident; 2524 asourcetoken.tokentype = ETokenType.ttidentifier; 2525 } 2526 } 2527 else if ( asourcetoken.tokencode == TBaseType.rrw_primary ) 2528 { 2529 // primary key [clustered | nonclustered ] ( column list) 2530 lcsteps = 2; 2531 lcprevtoken = asourcetoken; 2532 } 2533 else if ( asourcetoken.tokencode == TBaseType.rrw_foreign ) 2534 { 2535 // foreign key [clustered | nonclustered ] ( column list) 2536 lcsteps = 2; 2537 lcprevtoken = asourcetoken; 2538 } 2539 else if ( asourcetoken.tokencode == TBaseType.rrw_unique ) 2540 { 2541 // unique [clustered | nonclustered ] ( column list) 2542 lcsteps = 1; 2543 lcprevtoken = asourcetoken; 2544 } 2545 else if ( asourcetoken.issolidtoken() ) 2546 { 2547 if ( lcsteps > 0 ) 2548 { 2549 if ( !(TBaseType.mysametext("clustered",asourcetoken.toString()) 2550 || TBaseType.mysametext("nonclustered",asourcetoken.toString())) ) 2551 lcsteps--; 2552 } 2553 } 2554 2555 //System.out.println(asourcetoken); 2556 sourcetokenlist.add(asourcetoken); 2557 2558 2559 //flexer.yylexwrap(asourcetoken); 2560 asourcetoken = getanewsourcetoken(); 2561 if (asourcetoken != null){ 2562 yychar = asourcetoken.tokencode; 2563 }else{ 2564 yychar = 0; 2565 } 2566 2567 } 2568 2569 } 2570 2571boolean IsValidPlaceForDivToSqlplusCmd(TSourceTokenList pstlist, int pPos){ 2572 boolean ret = false; 2573 2574 if ((pPos <= 0) || (pPos > pstlist.size() - 1 ) ) return ret; 2575 //tokentext directly before div must be ttreturn without space appending it 2576 TSourceToken lcst = pstlist.get(pPos - 1); 2577 if (lcst.tokentype != ETokenType.ttreturn) { return ret;} 2578 2579 //I := Length(lcst.AsText); 2580 //if not (lcst.AsText[I] = ' ') then result := true; 2581 2582 if (!(lcst.getAstext().charAt(lcst.getAstext().length()-1) == ' ')) {ret = true;} 2583 2584 return ret; 2585} 2586 2587// place holder function, always return false 2588boolean isvalidsqlpluscmdInPostgresql(String astr){ 2589 return false; 2590} 2591 2592//boolean isvalidsqlpluscmd(String astr){ 2593// boolean ret = false; 2594// if (sqlpluskeywordList.size() == 0){ 2595// sqlpluskeywordList.put("ACC","1"); 2596// sqlpluskeywordList.put("ACCEPT","1"); 2597// sqlpluskeywordList.put("A","1"); 2598// sqlpluskeywordList.put("APPEND","1"); 2599// sqlpluskeywordList.put("ATTRIBUTE","1"); 2600// sqlpluskeywordList.put("BRE","1"); 2601// sqlpluskeywordList.put("BREAK","1"); 2602// sqlpluskeywordList.put("BTI","1"); 2603// sqlpluskeywordList.put("BTITLE","1"); 2604// sqlpluskeywordList.put("C","1"); 2605// sqlpluskeywordList.put("CHANGE","1"); 2606// sqlpluskeywordList.put("CL","1"); 2607// sqlpluskeywordList.put("CLEAR","1"); 2608// sqlpluskeywordList.put("COL","1"); 2609// sqlpluskeywordList.put("COLUMN","1"); 2610// sqlpluskeywordList.put("COMP","1"); 2611// sqlpluskeywordList.put("COMPUTE","1"); 2612// sqlpluskeywordList.put("CONN","1"); 2613// sqlpluskeywordList.put("CONNECT","1"); 2614// sqlpluskeywordList.put("COPY","1"); 2615// sqlpluskeywordList.put("DEF","1"); 2616// sqlpluskeywordList.put("DEFINE","1"); 2617// sqlpluskeywordList.put("DEL","1"); 2618// sqlpluskeywordList.put("DESC","1"); 2619// sqlpluskeywordList.put("DESCRIBE","1"); 2620// sqlpluskeywordList.put("DISC","1"); 2621// sqlpluskeywordList.put("DISCONNECT","1"); 2622// sqlpluskeywordList.put("ED","1"); 2623// sqlpluskeywordList.put("EDIT","1"); 2624// sqlpluskeywordList.put("EXEC","1"); 2625// sqlpluskeywordList.put("EXIT","1"); 2626// sqlpluskeywordList.put("QUIT","1"); 2627// sqlpluskeywordList.put("GET","1"); 2628// sqlpluskeywordList.put("HELP","1"); 2629// sqlpluskeywordList.put("HO","1"); 2630// sqlpluskeywordList.put("HOST","1"); 2631// sqlpluskeywordList.put("I","1"); 2632// sqlpluskeywordList.put("INPUT","1"); 2633// sqlpluskeywordList.put("L","1"); 2634// sqlpluskeywordList.put("LIST","1"); 2635// sqlpluskeywordList.put("PASSW","1"); 2636// sqlpluskeywordList.put("PASSWORD","1"); 2637// sqlpluskeywordList.put("PAU","1"); 2638// sqlpluskeywordList.put("PAUSE","1"); 2639// sqlpluskeywordList.put("PRI","1"); 2640// sqlpluskeywordList.put("PRINT","1"); 2641// sqlpluskeywordList.put("PROMPT","1"); 2642// sqlpluskeywordList.put("REM","1"); 2643// sqlpluskeywordList.put("REMARK","1"); 2644// sqlpluskeywordList.put("REPF","1"); 2645// sqlpluskeywordList.put("REPFOOTER","1"); 2646// sqlpluskeywordList.put("REPH","1"); 2647// sqlpluskeywordList.put("REPHEADER","1"); 2648// sqlpluskeywordList.put("R","1"); 2649// sqlpluskeywordList.put("RUN","1"); 2650// sqlpluskeywordList.put("SAV","1"); 2651// sqlpluskeywordList.put("SAVE","1"); 2652// sqlpluskeywordList.put("SET","1"); 2653// sqlpluskeywordList.put("SHO","1"); 2654// sqlpluskeywordList.put("SHOW","1"); 2655// sqlpluskeywordList.put("SPO","1"); 2656// sqlpluskeywordList.put("SPOOL","1"); 2657// sqlpluskeywordList.put("STA","1"); 2658// sqlpluskeywordList.put("START","1"); 2659// sqlpluskeywordList.put("STORE","1"); 2660// sqlpluskeywordList.put("TIMI","1"); 2661// sqlpluskeywordList.put("TIMING","1"); 2662// sqlpluskeywordList.put("TTI","1"); 2663// sqlpluskeywordList.put("TTITLE","1"); 2664// sqlpluskeywordList.put("UNDEF","1"); 2665// sqlpluskeywordList.put("UNDEFINE","1"); 2666// sqlpluskeywordList.put("VAR","1"); 2667// sqlpluskeywordList.put("VARIABLE","1"); 2668// sqlpluskeywordList.put("WHENEVER","1"); 2669// sqlpluskeywordList.put("@","1"); 2670// sqlpluskeywordList.put("@@","1"); 2671// } 2672// 2673// try{ 2674// ret = (Integer.parseInt( (String) sqlpluskeywordList.get(astr.toUpperCase()) ) ) == 1 ; 2675// }catch(NumberFormatException e){ 2676// ret = false; 2677// } 2678// 2679// return ret; 2680//} 2681 2682TSourceToken getprevsolidtoken(TSourceToken ptoken){ 2683 TSourceToken ret = null; 2684 TSourceTokenList lctokenlist = ptoken.container; 2685 if (lctokenlist != null){ 2686 if ((ptoken.posinlist > 0) && (lctokenlist.size() > ptoken.posinlist-1)) 2687 { 2688 if( !( 2689 (lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttwhitespace) 2690 ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttreturn) 2691 ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttsimplecomment) 2692 ||(lctokenlist.get(ptoken.posinlist-1).tokentype == ETokenType.ttbracketedcomment) 2693 )) 2694 { ret = lctokenlist.get(ptoken.posinlist-1);} 2695 else 2696 { ret = lctokenlist.nextsolidtoken(ptoken.posinlist-1,-1,false);} 2697 } 2698 } 2699 return ret; 2700} 2701 2702 void doredshifttexttotokenlist(){ 2703 2704 boolean insqlpluscmd = false; 2705 boolean isvalidplace = true; 2706 boolean waitingreturnforfloatdiv = false; 2707 boolean waitingreturnforsemicolon = false; 2708 boolean continuesqlplusatnewline = false; 2709 2710 2711 TSourceToken lct = null, prevst = null; 2712 2713 TSourceToken asourcetoken,lcprevst; 2714 int yychar; 2715 2716 asourcetoken = getanewsourcetoken(); 2717 if ( asourcetoken == null ) return; 2718 yychar = asourcetoken.tokencode; 2719 2720 while (yychar > 0) 2721 { 2722 2723 2724 sourcetokenlist.add(asourcetoken); 2725 switch(yychar){ 2726 case TBaseType.cmtdoublehyphen: 2727 case TBaseType.cmtslashstar: 2728 case TBaseType.lexspace:{ 2729 if (insqlpluscmd){ 2730 asourcetoken.insqlpluscmd = true; 2731 } 2732 break; 2733 } 2734 case TBaseType.lexnewline:{ 2735 if (insqlpluscmd){ 2736 insqlpluscmd = false; 2737 isvalidplace = true; 2738 2739 if (continuesqlplusatnewline) { 2740 insqlpluscmd = true; 2741 isvalidplace = false; 2742 asourcetoken.insqlpluscmd = true ; 2743 } 2744 } 2745 2746 if (waitingreturnforsemicolon){ 2747 isvalidplace = true; 2748 } 2749 if (waitingreturnforfloatdiv) 2750 { 2751 isvalidplace = true; 2752 lct.tokencode = TBaseType.sqlpluscmd; 2753 if (lct.tokentype != ETokenType.ttslash){ 2754 lct.tokentype = ETokenType.ttsqlpluscmd; 2755 } 2756 } 2757 flexer.insqlpluscmd = insqlpluscmd; 2758 break; 2759 } //case newline 2760 default:{ 2761 //solid tokentext 2762 continuesqlplusatnewline = false; 2763 waitingreturnforsemicolon = false; 2764 waitingreturnforfloatdiv = false; 2765 if (insqlpluscmd) 2766 { 2767 asourcetoken.insqlpluscmd = true ; 2768 if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 2769 } 2770 else 2771 { 2772 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 2773 {waitingreturnforsemicolon = true;} 2774 if ( (asourcetoken.tokentype == ETokenType.ttslash) 2775 // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then 2776 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 2777 { 2778 lct = asourcetoken; 2779 waitingreturnforfloatdiv = true; 2780 } 2781 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 2782 { 2783 asourcetoken.tokencode = TBaseType.sqlpluscmd; 2784 if (asourcetoken.tokentype != ETokenType.ttslash) 2785 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 2786 insqlpluscmd = true; 2787 flexer.insqlpluscmd = insqlpluscmd; 2788 } 2789 } 2790 isvalidplace = false; 2791 2792 if (asourcetoken.tokencode == TBaseType.rrw_redshift_rowtype) { 2793 TSourceToken stPercent = asourcetoken.searchToken('%', -1); 2794 if (stPercent != null) { 2795 stPercent.tokencode = TBaseType.rowtype_operator; 2796 } 2797 } 2798 2799 } 2800 } 2801 2802 //flexer.yylexwrap(asourcetoken); 2803 asourcetoken = getanewsourcetoken(); 2804 if (asourcetoken != null){ 2805 yychar = asourcetoken.tokencode; 2806 }else{ 2807 yychar = 0; 2808 2809 if (waitingreturnforfloatdiv) 2810 { // / at the end of line treat as sqlplus command 2811 //isvalidplace = true; 2812 lct.tokencode = TBaseType.sqlpluscmd; 2813 if (lct.tokentype != ETokenType.ttslash){ 2814 lct.tokentype = ETokenType.ttsqlpluscmd; 2815 } 2816 } 2817 } 2818 2819 if ((yychar == 0) && (prevst != null)) 2820 { 2821 } 2822 2823 }// while 2824 } 2825 2826 void doansitexttotokenlist(){ 2827 dodb2sqltexttotokenlist(); 2828 } 2829 void dogaussdbtexttotokenlist(){ 2830 2831 boolean insqlpluscmd = false; 2832 boolean isvalidplace = true; 2833 boolean waitingreturnforfloatdiv = false; 2834 boolean waitingreturnforsemicolon = false; 2835 boolean continuesqlplusatnewline = false; 2836 2837 TSourceToken lct = null, prevst = null; 2838 2839 TSourceToken asourcetoken,lcprevst; 2840 int yychar; 2841 2842 asourcetoken = getanewsourcetoken(); 2843 if ( asourcetoken == null ) return; 2844 yychar = asourcetoken.tokencode; 2845 2846 while (yychar > 0) 2847 { 2848 sourcetokenlist.add(asourcetoken); 2849 switch(yychar){ 2850 case TBaseType.cmtdoublehyphen: 2851 case TBaseType.cmtslashstar: 2852 case TBaseType.lexspace:{ 2853 if (insqlpluscmd){ 2854 asourcetoken.insqlpluscmd = true; 2855 } 2856 break; 2857 } 2858 case TBaseType.lexnewline:{ 2859 if (insqlpluscmd){ 2860 insqlpluscmd = false; 2861 isvalidplace = true; 2862 2863 if (continuesqlplusatnewline) { 2864 insqlpluscmd = true; 2865 isvalidplace = false; 2866 asourcetoken.insqlpluscmd = true ; 2867 } 2868 } 2869 2870 if (waitingreturnforsemicolon){ 2871 isvalidplace = true; 2872 } 2873 if (waitingreturnforfloatdiv) 2874 { 2875 isvalidplace = true; 2876 lct.tokencode = TBaseType.sqlpluscmd; 2877 if (lct.tokentype != ETokenType.ttslash){ 2878 lct.tokentype = ETokenType.ttsqlpluscmd; 2879 } 2880 } 2881 flexer.insqlpluscmd = insqlpluscmd; 2882 break; 2883 } //case newline 2884 default:{ 2885 //solid tokentext 2886 continuesqlplusatnewline = false; 2887 waitingreturnforsemicolon = false; 2888 waitingreturnforfloatdiv = false; 2889 if (insqlpluscmd) 2890 { 2891 asourcetoken.insqlpluscmd = true ; 2892 if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 2893 } 2894 else 2895 { 2896 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 2897 {waitingreturnforsemicolon = true;} 2898 if ( (asourcetoken.tokentype == ETokenType.ttslash) 2899 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 2900 { 2901 lct = asourcetoken; 2902 waitingreturnforfloatdiv = true; 2903 } 2904 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 2905 { 2906 asourcetoken.tokencode = TBaseType.sqlpluscmd; 2907 if (asourcetoken.tokentype != ETokenType.ttslash) 2908 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 2909 insqlpluscmd = true; 2910 flexer.insqlpluscmd = insqlpluscmd; 2911 } 2912 } 2913 isvalidplace = false; 2914 2915 // the inner keyword tokentext should be converted to TBaseType.ident when 2916 // next solid tokentext is not join 2917 2918 if (prevst != null) 2919 { 2920 if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER")) 2921 { 2922 if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN")) 2923 {prevst.tokencode = TBaseType.ident;} 2924 } 2925 2926 2927 if ((prevst.tokencode == TBaseType.rrw_not) 2928 && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE"))) 2929 { 2930 prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE"); 2931 } 2932 2933 } 2934 2935 if (asourcetoken.tokencode == TBaseType.rrw_inner) 2936 { 2937 prevst = asourcetoken; 2938 } 2939 else if (asourcetoken.tokencode == TBaseType.rrw_not) 2940 { 2941 prevst = asourcetoken; 2942 } 2943 else 2944 { prevst = null;} 2945 2946 if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD")) 2947 || (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) ) 2948 { 2949 // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS 2950 // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS 2951 // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view 2952 2953 lcprevst = getprevsolidtoken(asourcetoken); 2954 if (lcprevst != null) 2955 { 2956 if (lcprevst.tokencode == TBaseType.rrw_for) 2957 lcprevst.tokencode = TBaseType.rw_for1; 2958 } 2959 } 2960 2961 if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){ 2962 //keep keyword can be column alias, make keep in keep_denserankclause as a different token code 2963 TSourceToken stKeep = asourcetoken.searchToken(TBaseType.rrw_keep,-2); 2964 if ( stKeep != null){ 2965 stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank; 2966 } 2967 } 2968 2969 if ((asourcetoken.tokencode == TBaseType.rrw_postgresql_rowtype)||(asourcetoken.tokencode == TBaseType.rrw_postgresql_type)) { 2970 TSourceToken stPercent = asourcetoken.searchToken('%', -1); 2971 if (stPercent != null) { 2972 stPercent.tokencode = TBaseType.rowtype_operator; 2973 } 2974 } 2975 2976 if (asourcetoken.tokencode == TBaseType.JSON_EXIST) { 2977 TSourceToken stPercent = asourcetoken.searchToken('=', -1); 2978 if (stPercent != null) { // = ?, ? after = should not be treated as json exist operator 2979 asourcetoken.tokencode = TBaseType.ident; 2980 } 2981 } 2982 2983 if (asourcetoken.tokencode == TBaseType.rrw_update) { // on conflict do update in insert statement 2984 TSourceToken stDo = asourcetoken.searchToken(TBaseType.rrw_do, -1); 2985 if (stDo != null) { 2986 asourcetoken.tokencode = TBaseType.rrw_postgresql_do_update; 2987 } 2988 } 2989 2990 2991 } 2992 } 2993 2994 //flexer.yylexwrap(asourcetoken); 2995 asourcetoken = getanewsourcetoken(); 2996 if (asourcetoken != null){ 2997 yychar = asourcetoken.tokencode; 2998 }else{ 2999 yychar = 0; 3000 3001 if (waitingreturnforfloatdiv) 3002 { // / at the end of line treat as sqlplus command 3003 //isvalidplace = true; 3004 lct.tokencode = TBaseType.sqlpluscmd; 3005 if (lct.tokentype != ETokenType.ttslash){ 3006 lct.tokentype = ETokenType.ttsqlpluscmd; 3007 } 3008 } 3009 3010 } 3011 3012 if ((yychar == 0) && (prevst != null)) 3013 { 3014 if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER")) 3015 { prevst.tokencode = TBaseType.ident;} 3016 } 3017 3018 3019 } 3020 3021 3022 } 3023 void dopostgresqltexttotokenlist(){ 3024 3025 boolean insqlpluscmd = false; 3026 boolean isvalidplace = true; 3027 boolean waitingreturnforfloatdiv = false; 3028 boolean waitingreturnforsemicolon = false; 3029 boolean continuesqlplusatnewline = false; 3030 3031 TSourceToken lct = null, prevst = null; 3032 3033 TSourceToken asourcetoken,lcprevst; 3034 int yychar; 3035 3036 asourcetoken = getanewsourcetoken(); 3037 if ( asourcetoken == null ) return; 3038 yychar = asourcetoken.tokencode; 3039 3040 while (yychar > 0) 3041 { 3042 sourcetokenlist.add(asourcetoken); 3043 switch(yychar){ 3044 case TBaseType.cmtdoublehyphen: 3045 case TBaseType.cmtslashstar: 3046 case TBaseType.lexspace:{ 3047 if (insqlpluscmd){ 3048 asourcetoken.insqlpluscmd = true; 3049 } 3050 break; 3051 } 3052 case TBaseType.lexnewline:{ 3053 if (insqlpluscmd){ 3054 insqlpluscmd = false; 3055 isvalidplace = true; 3056 3057 if (continuesqlplusatnewline) { 3058 insqlpluscmd = true; 3059 isvalidplace = false; 3060 asourcetoken.insqlpluscmd = true ; 3061 } 3062 } 3063 3064 if (waitingreturnforsemicolon){ 3065 isvalidplace = true; 3066 } 3067 if (waitingreturnforfloatdiv) 3068 { 3069 isvalidplace = true; 3070 lct.tokencode = TBaseType.sqlpluscmd; 3071 if (lct.tokentype != ETokenType.ttslash){ 3072 lct.tokentype = ETokenType.ttsqlpluscmd; 3073 } 3074 } 3075 flexer.insqlpluscmd = insqlpluscmd; 3076 break; 3077 } //case newline 3078 default:{ 3079 //solid tokentext 3080 continuesqlplusatnewline = false; 3081 waitingreturnforsemicolon = false; 3082 waitingreturnforfloatdiv = false; 3083 if (insqlpluscmd) 3084 { 3085 asourcetoken.insqlpluscmd = true ; 3086 if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 3087 } 3088 else 3089 { 3090 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 3091 {waitingreturnforsemicolon = true;} 3092 if ( (asourcetoken.tokentype == ETokenType.ttslash) 3093 // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then 3094 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 3095 { 3096 lct = asourcetoken; 3097 waitingreturnforfloatdiv = true; 3098 } 3099 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 3100 { 3101 asourcetoken.tokencode = TBaseType.sqlpluscmd; 3102 if (asourcetoken.tokentype != ETokenType.ttslash) 3103 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 3104 insqlpluscmd = true; 3105 flexer.insqlpluscmd = insqlpluscmd; 3106 } 3107 } 3108 isvalidplace = false; 3109 3110 // the inner keyword tokentext should be convert to TBaseType.ident when 3111 // next solid tokentext is not join 3112 3113 if (prevst != null) 3114 { 3115 if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER")) 3116 { 3117 if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN")) 3118 {prevst.tokencode = TBaseType.ident;} 3119 } 3120 3121 3122 if ((prevst.tokencode == TBaseType.rrw_not) 3123 && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE"))) 3124 { 3125 prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE"); 3126 } 3127 3128 } 3129 3130 if (asourcetoken.tokencode == TBaseType.rrw_inner) 3131 { 3132 prevst = asourcetoken; 3133 } 3134 else if (asourcetoken.tokencode == TBaseType.rrw_not) 3135 { 3136 prevst = asourcetoken; 3137 } 3138 else 3139 { prevst = null;} 3140 3141 if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD")) 3142 || (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) ) 3143 { 3144 // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS 3145 // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS 3146 // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view 3147 3148 lcprevst = getprevsolidtoken(asourcetoken); 3149 if (lcprevst != null) 3150 { 3151 if (lcprevst.tokencode == TBaseType.rrw_for) 3152 lcprevst.tokencode = TBaseType.rw_for1; 3153 } 3154 } 3155 3156 if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){ 3157 //keep keyword can be column alias, make keep in keep_denserankclause as a different token code 3158 TSourceToken stKeep = asourcetoken.searchToken(TBaseType.rrw_keep,-2); 3159 if ( stKeep != null){ 3160 stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank; 3161 } 3162 } 3163 3164 if ((asourcetoken.tokencode == TBaseType.rrw_postgresql_rowtype)||(asourcetoken.tokencode == TBaseType.rrw_postgresql_type)) { 3165 TSourceToken stPercent = asourcetoken.searchToken('%', -1); 3166 if (stPercent != null) { 3167 stPercent.tokencode = TBaseType.rowtype_operator; 3168 } 3169 } 3170 3171 if (asourcetoken.tokencode == TBaseType.JSON_EXIST) { 3172 TSourceToken stPercent = asourcetoken.searchToken('=', -1); 3173 if (stPercent != null) { // = ?, ? after = should not be treated as json exist operator 3174 asourcetoken.tokencode = TBaseType.ident; 3175 } 3176 } 3177 3178 if (asourcetoken.tokencode == TBaseType.rrw_update) { // on conflict do update in insert statement 3179 TSourceToken stDo = asourcetoken.searchToken(TBaseType.rrw_do, -1); 3180 if (stDo != null) { 3181 asourcetoken.tokencode = TBaseType.rrw_postgresql_do_update; 3182 } 3183 } 3184 3185 3186 } 3187 } 3188 3189 //flexer.yylexwrap(asourcetoken); 3190 asourcetoken = getanewsourcetoken(); 3191 if (asourcetoken != null){ 3192 yychar = asourcetoken.tokencode; 3193 }else{ 3194 yychar = 0; 3195 3196 if (waitingreturnforfloatdiv) 3197 { // / at the end of line treat as sqlplus command 3198 //isvalidplace = true; 3199 lct.tokencode = TBaseType.sqlpluscmd; 3200 if (lct.tokentype != ETokenType.ttslash){ 3201 lct.tokentype = ETokenType.ttsqlpluscmd; 3202 } 3203 } 3204 3205 } 3206 3207 if ((yychar == 0) && (prevst != null)) 3208 { 3209 if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER")) 3210 { prevst.tokencode = TBaseType.ident;} 3211 } 3212 3213 3214 } 3215 3216 3217 } 3218 3219void dosnowflakesqltexttotokenlist(){ 3220 3221 boolean insqlpluscmd = false; 3222 boolean isvalidplace = true; 3223 boolean waitingreturnforfloatdiv = false; 3224 boolean waitingreturnforsemicolon = false; 3225 boolean continuesqlplusatnewline = false; 3226 3227 TSourceToken lct = null, prevst = null; 3228 3229 TSourceToken asourcetoken,lcprevst; 3230 int yychar; 3231 3232 asourcetoken = getanewsourcetoken(); 3233 if ( asourcetoken == null ) return; 3234 yychar = asourcetoken.tokencode; 3235 3236 while (yychar > 0) 3237 { 3238 sourcetokenlist.add(asourcetoken); 3239 switch(yychar){ 3240 case TBaseType.cmtdoublehyphen: 3241 case TBaseType.cmtslashstar: 3242 case TBaseType.lexspace:{ 3243 if (insqlpluscmd){ 3244 asourcetoken.insqlpluscmd = true; 3245 } 3246 break; 3247 } 3248 case TBaseType.lexnewline:{ 3249 if (insqlpluscmd){ 3250 insqlpluscmd = false; 3251 isvalidplace = true; 3252 3253 if (continuesqlplusatnewline) { 3254 insqlpluscmd = true; 3255 isvalidplace = false; 3256 asourcetoken.insqlpluscmd = true ; 3257 } 3258 } 3259 3260 if (waitingreturnforsemicolon){ 3261 isvalidplace = true; 3262 } 3263 if (waitingreturnforfloatdiv) 3264 { 3265 isvalidplace = true; 3266 lct.tokencode = TBaseType.sqlpluscmd; 3267 if (lct.tokentype != ETokenType.ttslash){ 3268 lct.tokentype = ETokenType.ttsqlpluscmd; 3269 } 3270 } 3271 flexer.insqlpluscmd = insqlpluscmd; 3272 break; 3273 } //case newline 3274 default:{ 3275 //solid tokentext 3276 continuesqlplusatnewline = false; 3277 waitingreturnforsemicolon = false; 3278 waitingreturnforfloatdiv = false; 3279 if (insqlpluscmd) 3280 { 3281 asourcetoken.insqlpluscmd = true ; 3282 if (asourcetoken.getAstext().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 3283 } 3284 else 3285 { 3286 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 3287 {waitingreturnforsemicolon = true;} 3288 if ( (asourcetoken.tokentype == ETokenType.ttslash) 3289 // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then 3290 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 3291 { 3292 lct = asourcetoken; 3293 waitingreturnforfloatdiv = true; 3294 } 3295 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 3296 { 3297 asourcetoken.tokencode = TBaseType.sqlpluscmd; 3298 if (asourcetoken.tokentype != ETokenType.ttslash) 3299 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 3300 insqlpluscmd = true; 3301 flexer.insqlpluscmd = insqlpluscmd; 3302 } 3303 } 3304 isvalidplace = false; 3305 3306 // the inner keyword tokentext should be convert to TBaseType.ident when 3307 // next solid tokentext is not join 3308 3309 if (prevst != null) 3310 { 3311 if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER")) 3312 { 3313 if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN")) 3314 {prevst.tokencode = TBaseType.ident;} 3315 } 3316 3317 3318 if ((prevst.tokencode == TBaseType.rrw_not) 3319 && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE"))) 3320 { 3321 prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE"); 3322 } 3323 3324 } 3325 3326 if (asourcetoken.tokencode == TBaseType.rrw_inner) 3327 { 3328 prevst = asourcetoken; 3329 } 3330 else if (asourcetoken.tokencode == TBaseType.rrw_not) 3331 { 3332 prevst = asourcetoken; 3333 } 3334 else 3335 { prevst = null;} 3336 3337 3338 } 3339 } 3340 3341 //flexer.yylexwrap(asourcetoken); 3342 asourcetoken = getanewsourcetoken(); 3343 if (asourcetoken != null){ 3344 yychar = asourcetoken.tokencode; 3345 }else{ 3346 yychar = 0; 3347 3348 if (waitingreturnforfloatdiv) 3349 { // / at the end of line treat as sqlplus command 3350 //isvalidplace = true; 3351 lct.tokencode = TBaseType.sqlpluscmd; 3352 if (lct.tokentype != ETokenType.ttslash){ 3353 lct.tokentype = ETokenType.ttsqlpluscmd; 3354 } 3355 } 3356 3357 } 3358 3359 if ((yychar == 0) && (prevst != null)) 3360 { 3361 if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER")) 3362 { prevst.tokencode = TBaseType.ident;} 3363 } 3364 3365 3366 } // while 3367 3368 3369} 3370 3371 void doverticatexttotokenlist(){ 3372 dopostgresqltexttotokenlist(); 3373 } 3374 3375 void docouchbasesqltexttotokenlist(){ 3376 dopostgresqltexttotokenlist(); 3377 } 3378 3379 void doclickhousesqltexttotokenlist(){ 3380 dopostgresqltexttotokenlist(); 3381 } 3382 3383 /** 3384 * Turn one token: `schema.table_name` into 3 tokens: `schema` . `table_name` 3385 * @param asourcetoken 3386 * @return 3387 */ 3388 int splitQualifiedNameInBacktick(TSourceToken asourcetoken){ 3389 int yychar = 0; 3390 3391 List<String> elephantList = Arrays.asList(TBaseType.getTextWithoutQuoted(asourcetoken.toString()).split("\\.")); 3392 int p = 0,offset=0; 3393 for(String s:elephantList){ 3394 TSourceToken pst = new TSourceToken("`"+s+"`"); 3395 pst.tokencode = asourcetoken.tokencode; 3396 pst.tokentype = asourcetoken.tokentype; 3397 pst.tokenstatus = asourcetoken.tokenstatus; 3398 pst.lineNo = asourcetoken.lineNo; 3399 pst.columnNo = asourcetoken.columnNo+offset; 3400 if (p==0) offset++;// this count the first ` token 3401 offset = offset+s.length(); 3402 pst.container = sourcetokenlist; 3403 if (p>0){// 第一个token使用被拆分前那个token的位置,从第二个开始的token,需要先把列表的位置指针加 1 3404 sourcetokenlist.curpos = sourcetokenlist.curpos+1; 3405 } 3406 pst.posinlist = sourcetokenlist.curpos; 3407 3408 sourcetokenlist.add(pst); 3409 yychar = pst.tokencode; 3410 3411 if (p != elephantList.size()-1){ 3412 //`schema.table_name`, add period token in the middle of the backtick included identifier. 3413 TSourceToken periodst = new TSourceToken("."); 3414 periodst.tokencode = '.'; 3415 periodst.tokentype = ETokenType.ttperiod; 3416 periodst.tokenstatus = asourcetoken.tokenstatus; 3417 periodst.lineNo = asourcetoken.lineNo; 3418 periodst.columnNo = asourcetoken.columnNo + offset; 3419 offset++; 3420 periodst.container = sourcetokenlist; 3421 sourcetokenlist.curpos = sourcetokenlist.curpos+1; 3422 periodst.posinlist = sourcetokenlist.curpos; 3423 sourcetokenlist.add(periodst); 3424 yychar = periodst.tokencode; 3425 } 3426 3427 p++; 3428 //System.out.println(s); 3429 } 3430 3431 return yychar; 3432 3433 } 3434 3435 void dobigquerysqltexttotokenlist(){ 3436 TSourceToken asourcetoken,lcprevst; 3437 int yychar; 3438 3439 3440 flexer.tmpDelimiter = ""; 3441 3442 asourcetoken = getanewsourcetoken(); 3443 if ( asourcetoken == null ) return; 3444 yychar = asourcetoken.tokencode; 3445 3446 while (yychar > 0) 3447 { 3448 if (asourcetoken != null){ 3449 sourcetokenlist.add(asourcetoken); 3450 } 3451 3452 asourcetoken = getanewsourcetoken(); 3453 if ( asourcetoken == null ) break; 3454 yychar = asourcetoken.tokencode; 3455 3456 // `schema.table_name` 3457 if ((asourcetoken.tokencode == TBaseType.ident) 3458 && (asourcetoken.toString().startsWith("`"))&& (asourcetoken.toString().endsWith("`")) 3459 && (asourcetoken.toString().indexOf(".")>0) 3460 ){ 3461 yychar = splitQualifiedNameInBacktick(asourcetoken); 3462 asourcetoken = null; 3463 } 3464 } 3465 } 3466 3467 void dosoqlsqltexttotokenlist(){ 3468 domssqlsqltexttotokenlist(); 3469 } 3470 3471void dogreenplumtexttotokenlist(){ 3472 3473 boolean insqlpluscmd = false; 3474 boolean isvalidplace = true; 3475 boolean waitingreturnforfloatdiv = false; 3476 boolean waitingreturnforsemicolon = false; 3477 boolean continuesqlplusatnewline = false; 3478 3479 TSourceToken lct = null, prevst = null; 3480 3481 TSourceToken asourcetoken,lcprevst; 3482 int yychar; 3483 3484 asourcetoken = getanewsourcetoken(); 3485 if ( asourcetoken == null ) return; 3486 yychar = asourcetoken.tokencode; 3487 3488 while (yychar > 0) 3489 { 3490 sourcetokenlist.add(asourcetoken); 3491 switch(yychar){ 3492 case TBaseType.cmtdoublehyphen: 3493 case TBaseType.cmtslashstar: 3494 case TBaseType.lexspace:{ 3495 if (insqlpluscmd){ 3496 asourcetoken.insqlpluscmd = true; 3497 } 3498 break; 3499 } 3500 case TBaseType.lexnewline:{ 3501 if (insqlpluscmd){ 3502 insqlpluscmd = false; 3503 isvalidplace = true; 3504 3505 if (continuesqlplusatnewline) { 3506 insqlpluscmd = true; 3507 isvalidplace = false; 3508 asourcetoken.insqlpluscmd = true ; 3509 } 3510 } 3511 3512 if (waitingreturnforsemicolon){ 3513 isvalidplace = true; 3514 } 3515 if (waitingreturnforfloatdiv) 3516 { 3517 isvalidplace = true; 3518 lct.tokencode = TBaseType.sqlpluscmd; 3519 if (lct.tokentype != ETokenType.ttslash){ 3520 lct.tokentype = ETokenType.ttsqlpluscmd; 3521 } 3522 } 3523 flexer.insqlpluscmd = insqlpluscmd; 3524 break; 3525 } //case newline 3526 default:{ 3527 //solid tokentext 3528 continuesqlplusatnewline = false; 3529 waitingreturnforsemicolon = false; 3530 waitingreturnforfloatdiv = false; 3531 if (insqlpluscmd) 3532 { 3533 asourcetoken.insqlpluscmd = true ; 3534 if (asourcetoken.toString().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 3535 } 3536 else 3537 { 3538 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 3539 {waitingreturnforsemicolon = true;} 3540 if ( (asourcetoken.tokentype == ETokenType.ttslash) 3541 // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then 3542 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 3543 { 3544 lct = asourcetoken; 3545 waitingreturnforfloatdiv = true; 3546 } 3547 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 3548 { 3549 asourcetoken.tokencode = TBaseType.sqlpluscmd; 3550 if (asourcetoken.tokentype != ETokenType.ttslash) 3551 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 3552 insqlpluscmd = true; 3553 flexer.insqlpluscmd = insqlpluscmd; 3554 } 3555 } 3556 isvalidplace = false; 3557 3558 // the inner keyword tokentext should be convert to TBaseType.ident when 3559 // next solid tokentext is not join 3560 3561 if (prevst != null) 3562 { 3563 if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER")) 3564 { 3565 if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN")) 3566 {prevst.tokencode = TBaseType.ident;} 3567 } 3568 3569 3570 if ((prevst.tokencode == TBaseType.rrw_not) 3571 && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE"))) 3572 { 3573 prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE"); 3574 } 3575 3576 } 3577 3578 if (asourcetoken.tokencode == TBaseType.rrw_inner) 3579 { 3580 prevst = asourcetoken; 3581 } 3582 else if (asourcetoken.tokencode == TBaseType.rrw_not) 3583 { 3584 prevst = asourcetoken; 3585 } 3586 else 3587 { prevst = null;} 3588 3589 if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD")) 3590 || (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) ) 3591 { 3592 // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS 3593 // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS 3594 // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view 3595 3596 lcprevst = getprevsolidtoken(asourcetoken); 3597 if (lcprevst != null) 3598 { 3599 if (lcprevst.tokencode == TBaseType.rrw_for) 3600 lcprevst.tokencode = TBaseType.rw_for1; 3601 } 3602 } 3603 3604 if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){ 3605 //keep keyword can be column alias, make keep in keep_denserankclause as a different token code 3606 TSourceToken stKeep = asourcetoken.searchToken(TBaseType.rrw_keep,-2); 3607 if ( stKeep != null){ 3608 stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank; 3609 } 3610 } 3611 3612 if (asourcetoken.tokencode == TBaseType.rrw_greenplum_rowtype) { 3613 TSourceToken stPercent = asourcetoken.searchToken('%', -1); 3614 if (stPercent != null) { 3615 stPercent.tokencode = TBaseType.rowtype_operator; 3616 } 3617 } 3618 3619 3620 } 3621 } 3622 3623 //flexer.yylexwrap(asourcetoken); 3624 asourcetoken = getanewsourcetoken(); 3625 if (asourcetoken != null){ 3626 yychar = asourcetoken.tokencode; 3627 }else{ 3628 yychar = 0; 3629 3630 if (waitingreturnforfloatdiv) 3631 { // / at the end of line treat as sqlplus command 3632 //isvalidplace = true; 3633 lct.tokencode = TBaseType.sqlpluscmd; 3634 if (lct.tokentype != ETokenType.ttslash){ 3635 lct.tokentype = ETokenType.ttsqlpluscmd; 3636 } 3637 } 3638 3639 } 3640 3641 if ((yychar == 0) && (prevst != null)) 3642 { 3643 if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER")) 3644 { prevst.tokencode = TBaseType.ident;} 3645 } 3646 3647 3648 } 3649 3650 3651 } 3652 3653void donetezzatexttotokenlist(){ 3654 3655 boolean insqlpluscmd = false; 3656 boolean isvalidplace = true; 3657 boolean waitingreturnforfloatdiv = false; 3658 boolean waitingreturnforsemicolon = false; 3659 boolean continuesqlplusatnewline = false; 3660 3661 TSourceToken lct = null, prevst = null; 3662 3663 TSourceToken asourcetoken,lcprevst; 3664 int yychar; 3665 3666 asourcetoken = getanewsourcetoken(); 3667 if ( asourcetoken == null ) return; 3668 yychar = asourcetoken.tokencode; 3669 3670 while (yychar > 0) 3671 { 3672 sourcetokenlist.add(asourcetoken); 3673 switch(yychar){ 3674 case TBaseType.cmtdoublehyphen: 3675 case TBaseType.cmtslashstar: 3676 case TBaseType.lexspace:{ 3677 if (insqlpluscmd){ 3678 asourcetoken.insqlpluscmd = true; 3679 } 3680 break; 3681 } 3682 case TBaseType.lexnewline:{ 3683 if (insqlpluscmd){ 3684 insqlpluscmd = false; 3685 isvalidplace = true; 3686 3687 if (continuesqlplusatnewline) { 3688 insqlpluscmd = true; 3689 isvalidplace = false; 3690 asourcetoken.insqlpluscmd = true ; 3691 } 3692 } 3693 3694 if (waitingreturnforsemicolon){ 3695 isvalidplace = true; 3696 } 3697 if (waitingreturnforfloatdiv) 3698 { 3699 isvalidplace = true; 3700 lct.tokencode = TBaseType.sqlpluscmd; 3701 if (lct.tokentype != ETokenType.ttslash){ 3702 lct.tokentype = ETokenType.ttsqlpluscmd; 3703 } 3704 } 3705 flexer.insqlpluscmd = insqlpluscmd; 3706 break; 3707 } //case newline 3708 default:{ 3709 //solid tokentext 3710 continuesqlplusatnewline = false; 3711 waitingreturnforsemicolon = false; 3712 waitingreturnforfloatdiv = false; 3713 if (insqlpluscmd) 3714 { 3715 asourcetoken.insqlpluscmd = true ; 3716 if (asourcetoken.getAstext().equalsIgnoreCase("-")) { continuesqlplusatnewline = true;} 3717 } 3718 else 3719 { 3720 if (asourcetoken.tokentype == ETokenType.ttsemicolon) 3721 {waitingreturnforsemicolon = true;} 3722 if ( (asourcetoken.tokentype == ETokenType.ttslash) 3723 // and (isvalidplace or sourcetokenlist.TokenBeforeCurToken(#10,false,false,false)) then 3724 && (isvalidplace || (IsValidPlaceForDivToSqlplusCmd(sourcetokenlist,asourcetoken.posinlist)) ) ) 3725 { 3726 lct = asourcetoken; 3727 waitingreturnforfloatdiv = true; 3728 } 3729 if ((isvalidplace) && isvalidsqlpluscmdInPostgresql(asourcetoken.toString()) ) 3730 { 3731 asourcetoken.tokencode = TBaseType.sqlpluscmd; 3732 if (asourcetoken.tokentype != ETokenType.ttslash) 3733 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 3734 insqlpluscmd = true; 3735 flexer.insqlpluscmd = insqlpluscmd; 3736 } 3737 } 3738 isvalidplace = false; 3739 3740 // the inner keyword tokentext should be convert to TBaseType.ident when 3741 // next solid tokentext is not join 3742 3743 if (prevst != null) 3744 { 3745 if (prevst.tokencode == TBaseType.rrw_inner)//flexer.getkeywordvalue("INNER")) 3746 { 3747 if (asourcetoken.tokencode != flexer.getkeywordvalue("JOIN")) 3748 {prevst.tokencode = TBaseType.ident;} 3749 } 3750 3751 3752 if ((prevst.tokencode == TBaseType.rrw_not) 3753 && (asourcetoken.tokencode == flexer.getkeywordvalue("DEFERRABLE"))) 3754 { 3755 prevst.tokencode = flexer.getkeywordvalue("NOT_DEFERRABLE"); 3756 } 3757 3758 } 3759 3760 if (asourcetoken.tokencode == TBaseType.rrw_inner) 3761 { 3762 prevst = asourcetoken; 3763 } 3764 else if (asourcetoken.tokencode == TBaseType.rrw_not) 3765 { 3766 prevst = asourcetoken; 3767 } 3768 else 3769 { prevst = null;} 3770 3771 if ((asourcetoken.tokencode == flexer.getkeywordvalue("DIRECT_LOAD")) 3772 || (asourcetoken.tokencode == flexer.getkeywordvalue("ALL")) ) 3773 { 3774 // RW_COMPRESS RW_FOR RW_ALL RW_OPERATIONS 3775 // RW_COMPRESS RW_FOR RW_DIRECT_LOAD RW_OPERATIONS 3776 // change rw_for to TBaseType.rw_for1, it conflicts with compress for update in create materialized view 3777 3778 lcprevst = getprevsolidtoken(asourcetoken); 3779 if (lcprevst != null) 3780 { 3781 if (lcprevst.tokencode == TBaseType.rrw_for) 3782 lcprevst.tokencode = TBaseType.rw_for1; 3783 } 3784 } 3785 3786 if (asourcetoken.tokencode == TBaseType.rrw_dense_rank){ 3787 //keep keyword can be column alias, make keep in keep_denserankclause as a different token code 3788 TSourceToken stKeep = asourcetoken.searchToken(TBaseType.rrw_keep,-2); 3789 if ( stKeep != null){ 3790 stKeep.tokencode = TBaseType.rrw_keep_before_dense_rank; 3791 } 3792 } 3793 3794 3795 } 3796 } 3797 3798 //flexer.yylexwrap(asourcetoken); 3799 asourcetoken = getanewsourcetoken(); 3800 if (asourcetoken != null){ 3801 yychar = asourcetoken.tokencode; 3802 }else{ 3803 yychar = 0; 3804 3805 if (waitingreturnforfloatdiv) 3806 { // / at the end of line treat as sqlplus command 3807 //isvalidplace = true; 3808 lct.tokencode = TBaseType.sqlpluscmd; 3809 if (lct.tokentype != ETokenType.ttslash){ 3810 lct.tokentype = ETokenType.ttsqlpluscmd; 3811 } 3812 } 3813 3814 } 3815 3816 if ((yychar == 0) && (prevst != null)) 3817 { 3818 if (prevst.tokencode == TBaseType.rrw_inner)// flexer.getkeywordvalue("RW_INNER")) 3819 { prevst.tokencode = TBaseType.ident;} 3820 } 3821 3822 3823 } 3824} 3825 3826private boolean spaceAtTheEndOfReturnToken(String s){ 3827 int pos = 0; 3828 if (s == null) return false; 3829 if (s.length() == 0) return false; 3830 3831 return ((s.charAt(s.length() -1 ) == ' ')||(s.charAt(s.length() -1 ) == '\t')); 3832} 3833 3834private int countLines(String s){ 3835 int pos = 0, lf = 0, cr = 0; 3836 3837 while (pos < s.length()) { 3838 if (s.charAt(pos) == '\r') { 3839 cr++; 3840 pos++; 3841 continue; 3842 } 3843 if (s.charAt(pos) == '\n') { 3844 lf++; 3845 pos++; 3846 continue; 3847 } 3848 3849 if (s.charAt(pos) == ' ') { 3850 pos++; 3851 continue; 3852 } 3853 break; 3854 } 3855 3856 if (lf >= cr) return lf; 3857 else return cr; 3858 3859 } 3860 3861 3862void dodb2sqltexttotokenlist(){ 3863// treat echo, ! of db2 at the begin of each line as 3864// oracle sqlplus command 3865 3866 boolean insqlpluscmd = false; 3867 boolean isvalidplace = true; 3868 int jdbc_escape_nest = 0; 3869// isSolidTokenStart := false; 3870 3871// tempsourcetokenlist.clear; 3872 3873 TSourceToken asourcetoken,lcprevst; 3874 int yychar; 3875 3876 asourcetoken = getanewsourcetoken(); 3877 3878 if ( asourcetoken == null ) return; 3879 yychar = asourcetoken.tokencode; 3880 3881 3882 while (yychar > 0) 3883 { 3884 3885 switch (yychar){ 3886 case TBaseType.lexnewline: 3887 { 3888 insqlpluscmd = false; 3889 isvalidplace = true; 3890 break; 3891 } 3892 case TBaseType.cmtdoublehyphen: 3893 { 3894 if (asourcetoken.toString().toLowerCase().indexOf("scriptoptions")>=0) 3895 { 3896 asourcetoken.tokencode = TBaseType.scriptoptions; 3897 asourcetoken.tokentype = ETokenType.ttidentifier; 3898 } 3899 3900 if (insqlpluscmd) 3901 { 3902 asourcetoken.insqlpluscmd = true; 3903 } 3904 break; 3905 } 3906 case TBaseType.rrw_jdbc_escape_fn: { 3907 jdbc_escape_nest++; 3908 asourcetoken.tokencode = TBaseType.lexspace; 3909 break; 3910 } 3911 case TBaseType.rrw_jdbc_escape_end: { 3912 jdbc_escape_nest--; 3913 asourcetoken.tokencode = TBaseType.lexspace; 3914 break; 3915 } 3916 default: //solid tokentext 3917 { 3918 if ((asourcetoken.tokencode == TBaseType.rrw_rr) 3919 || (asourcetoken.tokencode == TBaseType.rrw_rs) 3920 || (asourcetoken.tokencode == TBaseType.rrw_cs) 3921 || (asourcetoken.tokencode == TBaseType.rrw_ur) 3922 ) 3923 { 3924 // change with keyword in isolation clause to rrw_with_isolation 3925 // so opt_restriction_clause in create view worked correctly 3926 lcprevst = getprevsolidtoken(asourcetoken); 3927 if (lcprevst != null) 3928 { 3929 if (lcprevst.tokencode == TBaseType.rrw_with) 3930 lcprevst.tokencode = TBaseType.rrw_with_isolation; 3931 } 3932 } 3933 3934 if (insqlpluscmd) 3935 { 3936 //asourcetoken.TokenCode := TBaseType.sqlpluscmd; 3937 asourcetoken.insqlpluscmd = true; 3938 } 3939 else 3940 { 3941 if (isvalidplace){ 3942 // System.out.println(asourcetoken.astext); 3943 if (TBaseType.mycomparetext(asourcetoken.toString().toLowerCase(),"echo") == 0 ) 3944 { 3945 // System.out.println("finded "); 3946 asourcetoken.tokencode = TBaseType.sqlpluscmd; 3947 if (asourcetoken.tokentype != ETokenType.ttslash) 3948 {asourcetoken.tokentype = ETokenType.ttsqlpluscmd;} 3949 asourcetoken.insqlpluscmd = true; 3950 insqlpluscmd = true; 3951 } 3952 } 3953 } 3954 isvalidplace = false; 3955 3956 break; 3957 } //end of solid tokentext 3958 } //switch 3959 3960// TBaseType.lexnewline 3961 3962 sourcetokenlist.add(asourcetoken); 3963 3964 asourcetoken = getanewsourcetoken(); 3965 if ( asourcetoken == null ) break; 3966 yychar = asourcetoken.tokencode; 3967 3968 } //while 3969 3970} 3971 3972 void doteradatatexttotokenlist(){ 3973 3974 TSourceToken asourcetoken,lcprevst; 3975 int yychar; 3976 3977 asourcetoken = getanewsourcetoken(); 3978 if ( asourcetoken == null ) return; 3979 yychar = asourcetoken.tokencode; 3980 3981 while (yychar > 0) 3982 { 3983 sourcetokenlist.add(asourcetoken); 3984 asourcetoken = getanewsourcetoken(); 3985 if ( asourcetoken == null ) break; 3986 3987 if ((asourcetoken.tokencode == TBaseType.rrw_casespecific) 3988 ||(asourcetoken.tokencode == TBaseType.rrw_teradata_cs)) 3989 { 3990 /* change not to not1 to make "not null column constriants" work correctly */ 3991 // |RW_NOT1 RW_CASESPECIFIC 3992 3993 lcprevst = getprevsolidtoken(asourcetoken); 3994 if (lcprevst != null) 3995 { 3996 if (lcprevst.tokencode == TBaseType.rrw_not) 3997 lcprevst.tokencode = TBaseType.rw_not1; 3998 } 3999 } else if (asourcetoken.tokencode == ';'){ 4000 lcprevst = getprevsolidtoken(asourcetoken); 4001 if (lcprevst != null) 4002 { 4003 if (lcprevst.tokencode == ';') 4004 asourcetoken.tokencode = TBaseType.sqlpluscmd; 4005 } 4006 } else if (asourcetoken.tokencode == TBaseType.variable){ // mantisbt/view.php?id=972 4007 if (asourcetoken.toString().toLowerCase().endsWith("begin")){ //MYPROC :BEGIN 4008 asourcetoken.tokencode = TBaseType.rrw_begin; 4009 asourcetoken.tokentype = ETokenType.ttkeyword; 4010 4011 lcprevst = getprevsolidtoken(asourcetoken); 4012 if (lcprevst != null) 4013 { 4014 lcprevst.tokencode = TBaseType.mslabel; 4015 } 4016 4017 } 4018 }else if (asourcetoken.tokencode == TCustomLexer.UNICODE_ENCODE_ID){ 4019 if (asourcetoken.toString().endsWith("008D")){ // REVERSE LINE FEED, https://codepoints.net/U+008D?lang=en 4020 asourcetoken.tokencode = TBaseType.lexspace; 4021 }else{ 4022 asourcetoken.tokencode = TBaseType.ident; 4023 } 4024 } 4025 4026 4027 yychar = asourcetoken.tokencode; 4028 } 4029 4030 } 4031 4032void docommonsqltexttotokenlist(){ 4033 4034 TSourceToken asourcetoken,lcprevst; 4035 int yychar; 4036 4037 asourcetoken = getanewsourcetoken(); 4038 if ( asourcetoken == null ) return; 4039 yychar = asourcetoken.tokencode; 4040 4041 while (yychar > 0) 4042 { 4043 sourcetokenlist.add(asourcetoken); 4044 asourcetoken = getanewsourcetoken(); 4045 if ( asourcetoken == null ) break; 4046 yychar = asourcetoken.tokencode; 4047 } 4048 4049} 4050 void doodbcsqltexttotokenlist(){ 4051 boolean insideODBC = false; 4052 TSourceToken odbcPrefix = null; 4053 domssqlsqltexttotokenlist(); 4054 for (int i=0 ; i<sourcetokenlist.size();i++) { 4055 TSourceToken ast = sourcetokenlist.get(i); 4056 if ((ast.tokencode == '{')||(ast.tokencode == TBaseType.odbc_esc_prefix)) 4057 { 4058 insideODBC = true; 4059 odbcPrefix = ast; 4060 } 4061 if ((ast.tokencode == '}')||(ast.tokencode == TBaseType.odbc_esc_terminator)) 4062 { 4063 insideODBC = false; 4064 odbcPrefix = null; 4065 } 4066 if (((ast.tokencode == TBaseType.rrw_odbc_d) 4067 ||(ast.tokencode == TBaseType.rrw_odbc_t) 4068 ||(ast.tokencode == TBaseType.rrw_odbc_ts) 4069 ||(ast.tokencode == TBaseType.rrw_odbc_fn) 4070 ||(ast.tokencode == TBaseType.rrw_odbc_oj) 4071 )&&(!insideODBC)) { 4072 ast.tokencode = TBaseType.ident; 4073 } 4074 4075 if ((ast.tokencode == TBaseType.rrw_call)&&(insideODBC)){ 4076 odbcPrefix.setLinkToken(ast); 4077 } 4078 } 4079 } 4080 4081void dodaxsqltexttotokenlist(){ 4082 4083 TSourceToken asourcetoken,lcprevst; 4084 int yychar; 4085 4086 asourcetoken = getanewsourcetoken(); 4087 if ( asourcetoken == null ) return; 4088 yychar = asourcetoken.tokencode; 4089 4090 while (yychar > 0) 4091 { 4092 sourcetokenlist.add(asourcetoken); 4093 asourcetoken = getanewsourcetoken(); 4094 if ( asourcetoken == null ) break; 4095 yychar = asourcetoken.tokencode; 4096 } 4097 4098} 4099 4100 4101void dohanasqltexttotokenlist(){ 4102 4103 TSourceToken asourcetoken,lcprevst; 4104 int yychar; 4105 4106 asourcetoken = getanewsourcetoken(); 4107 if ( asourcetoken == null ) return; 4108 yychar = asourcetoken.tokencode; 4109 4110 while (yychar > 0) 4111 { 4112 sourcetokenlist.add(asourcetoken); 4113 asourcetoken = getanewsourcetoken(); 4114 if ( asourcetoken == null ) break; 4115 yychar = asourcetoken.tokencode; 4116 } 4117 4118} 4119 4120void dohivetexttotokenlist(){ 4121 4122 TSourceToken asourcetoken,lcprevst; 4123 int yychar; 4124 4125 asourcetoken = getanewsourcetoken(); 4126 if ( asourcetoken == null ) return; 4127 yychar = asourcetoken.tokencode; 4128 4129 while (yychar > 0) 4130 { 4131 if (asourcetoken != null){ 4132 sourcetokenlist.add(asourcetoken); 4133 } 4134 asourcetoken = getanewsourcetoken(); 4135 if ( asourcetoken == null ) break; 4136 if (asourcetoken.tokencode == TBaseType.rrw_map){ 4137 TSourceToken token = asourcetoken.searchToken(')',-1); 4138 if (token != null){ 4139 asourcetoken.tokencode = TBaseType.ident; 4140 } 4141 }else if (asourcetoken.tokencode == '('){ 4142// TSourceToken token = asourcetoken.searchToken(TBaseType.ident,-1); 4143// if (token != null){ 4144// token.tokencode = TBaseType.HIVE_FUNC_IDENT; 4145// } 4146 } 4147 yychar = asourcetoken.tokencode; 4148 4149 // `schema.table_name` 4150 if ((asourcetoken.tokencode == TBaseType.ident) 4151 && (asourcetoken.toString().startsWith("`"))&& (asourcetoken.toString().endsWith("`")) 4152 && (asourcetoken.toString().indexOf(".")>0) 4153 ){ 4154 yychar = splitQualifiedNameInBacktick(asourcetoken); 4155 asourcetoken = null; 4156 } 4157 4158 } 4159 4160} 4161 4162void doimpalatexttotokenlist(){ 4163 dohivetexttotokenlist(); 4164} 4165 4166void checkMySQLCommentToken(TSourceToken cmtToken){ 4167// if (cmtToken.tokencode == TBaseType.cmtdoublehyphen){ 4168// if ((cmtToken.toString().startsWith("--"))){ 4169// if (cmtToken.toString().length() > 2){ 4170// if (cmtToken.toString().charAt(2) != ' '){ 4171// this.syntaxErrors.add(new TSyntaxError(cmtToken.toString(), 4172// cmtToken.lineNo, 4173// cmtToken.columnNo, 4174// "requires a space after the initial \"--\" ",EErrorType.sperror,10010 4175// )); 4176// } 4177// } 4178// // there should be 4179// } 4180// } 4181} 4182 void dosparksqltexttotokenlist(){ 4183 TSourceToken asourcetoken,lcprevst; 4184 int yychar; 4185 boolean startDelimiter = false; 4186 4187 flexer.tmpDelimiter = ""; 4188 4189 asourcetoken = getanewsourcetoken(); 4190 if ( asourcetoken == null ) return; 4191 yychar = asourcetoken.tokencode; 4192 4193 4194 4195 4196 while (yychar > 0) 4197 { 4198 sourcetokenlist.add(asourcetoken); 4199 asourcetoken = getanewsourcetoken(); 4200 if ( asourcetoken == null ) break; 4201 checkMySQLCommentToken(asourcetoken); 4202 4203 if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){ 4204 startDelimiter = false; 4205 flexer.tmpDelimiter = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext(); 4206 } 4207 4208 4209 if (asourcetoken.tokencode == TBaseType.rrw_rollup) 4210 { 4211 // with rollup 4212 4213 lcprevst = getprevsolidtoken(asourcetoken); 4214 if (lcprevst != null) 4215 { 4216 if (lcprevst.tokencode == TBaseType.rrw_with) 4217 lcprevst.tokencode = TBaseType.with_rollup; 4218 } 4219 } 4220 4221 yychar = asourcetoken.tokencode; 4222 } 4223 4224 } 4225 4226 void doathenatexttotokenlist(){ 4227 TSourceToken asourcetoken,lcprevst; 4228 int yychar; 4229 boolean startDelimiter = false; 4230 4231 flexer.tmpDelimiter = ""; 4232 4233 asourcetoken = getanewsourcetoken(); 4234 if ( asourcetoken == null ) return; 4235 yychar = asourcetoken.tokencode; 4236 4237 4238 4239 4240 while (yychar > 0) 4241 { 4242 sourcetokenlist.add(asourcetoken); 4243 asourcetoken = getanewsourcetoken(); 4244 if ( asourcetoken == null ) break; 4245 checkMySQLCommentToken(asourcetoken); 4246 4247 if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){ 4248 startDelimiter = false; 4249 flexer.tmpDelimiter = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext(); 4250 } 4251 4252 4253 yychar = asourcetoken.tokencode; 4254 } 4255 4256 } 4257 4258 void dodatabrickstexttotokenlist(){ 4259 TSourceToken asourcetoken,lcprevst; 4260 int yychar; 4261 boolean startDelimiter = false; 4262 4263 flexer.tmpDelimiter = ""; 4264 4265 asourcetoken = getanewsourcetoken(); 4266 if ( asourcetoken == null ) return; 4267 yychar = asourcetoken.tokencode; 4268 4269 4270 4271 4272 while (yychar > 0) 4273 { 4274 sourcetokenlist.add(asourcetoken); 4275 asourcetoken = getanewsourcetoken(); 4276 if ( asourcetoken == null ) break; 4277 checkMySQLCommentToken(asourcetoken); 4278 4279 if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){ 4280 startDelimiter = false; 4281 flexer.tmpDelimiter = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext(); 4282 } 4283 4284 4285 yychar = asourcetoken.tokencode; 4286 } 4287 4288 } 4289 void doprestotexttotokenlist(){ 4290 TSourceToken asourcetoken,lcprevst; 4291 int yychar; 4292 boolean startDelimiter = false; 4293 4294 flexer.tmpDelimiter = ""; 4295 4296 asourcetoken = getanewsourcetoken(); 4297 if ( asourcetoken == null ) return; 4298 yychar = asourcetoken.tokencode; 4299 4300 4301 4302 4303 while (yychar > 0) 4304 { 4305 sourcetokenlist.add(asourcetoken); 4306 asourcetoken = getanewsourcetoken(); 4307 if ( asourcetoken == null ) break; 4308 checkMySQLCommentToken(asourcetoken); 4309 4310 if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){ 4311 startDelimiter = false; 4312 flexer.tmpDelimiter = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext(); 4313 } 4314 4315 4316 yychar = asourcetoken.tokencode; 4317 } 4318 4319 } 4320 4321void domysqltexttotokenlist(){ 4322 4323 TSourceToken asourcetoken,lcprevst; 4324 int yychar; 4325 boolean startDelimiter = false; 4326 4327 flexer.tmpDelimiter = ""; 4328 4329 asourcetoken = getanewsourcetoken(); 4330 if ( asourcetoken == null ) return; 4331 yychar = asourcetoken.tokencode; 4332 checkMySQLCommentToken(asourcetoken); 4333 4334 if ((asourcetoken.tokencode == TBaseType.rrw_mysql_delimiter)){ 4335 startDelimiter = true; 4336 } 4337 4338 while (yychar > 0) 4339 { 4340 sourcetokenlist.add(asourcetoken); 4341 asourcetoken = getanewsourcetoken(); 4342 if ( asourcetoken == null ) break; 4343 checkMySQLCommentToken(asourcetoken); 4344 4345 if ((asourcetoken.tokencode == TBaseType.lexnewline)&&(startDelimiter)){ 4346 startDelimiter = false; 4347 flexer.tmpDelimiter = sourcetokenlist.get(sourcetokenlist.size() - 1).getAstext(); 4348 } 4349 4350 if ((asourcetoken.tokencode == TBaseType.rrw_mysql_delimiter)){ 4351 startDelimiter = true; 4352 } 4353 4354 if (asourcetoken.tokencode == TBaseType.rrw_rollup) 4355 { 4356 // with rollup 4357 4358 lcprevst = getprevsolidtoken(asourcetoken); 4359 if (lcprevst != null) 4360 { 4361 if (lcprevst.tokencode == TBaseType.rrw_with) 4362 lcprevst.tokencode = TBaseType.with_rollup; 4363 } 4364 } 4365 4366 if( (asourcetoken.tokencode == TBaseType.rrw_mysql_d) 4367 ||(asourcetoken.tokencode == TBaseType.rrw_mysql_t) 4368 ||(asourcetoken.tokencode == TBaseType.rrw_mysql_ts) 4369 ) 4370 { 4371 // odbc date constant { d 'str' } 4372 lcprevst = getprevsolidtoken(asourcetoken); 4373 if (lcprevst != null) 4374 { 4375 if (lcprevst.tokencode != '{') 4376 asourcetoken.tokencode = TBaseType.ident; 4377 } 4378 } 4379 4380 4381 yychar = asourcetoken.tokencode; 4382 } 4383 4384 } 4385 4386void doMdxtexttotokenlist(){ 4387 4388 TSourceToken asourcetoken,lcprevst; 4389 int yychar; 4390 4391 asourcetoken = getanewsourcetoken(); 4392 if ( asourcetoken == null ) return; 4393 yychar = asourcetoken.tokencode; 4394 4395 while (yychar > 0) 4396 { 4397 sourcetokenlist.add(asourcetoken); 4398 asourcetoken = getanewsourcetoken(); 4399 if ( asourcetoken == null ) break; 4400 yychar = asourcetoken.tokencode; 4401 } 4402 4403} 4404 4405void dosqltexttotokenlist(){ 4406 switch(dbVendor){ 4407 case dbvmssql: 4408 case dbvazuresql: 4409 { 4410 domssqlsqltexttotokenlist(); 4411 break; 4412 } 4413 case dbvinformix:{ 4414 doinformixtexttotokenlist(); 4415 break; 4416 } 4417 case dbvsybase:{ 4418 dosybasesqltexttotokenlist(); 4419 break; 4420 } 4421 case dbvdb2:{ 4422 dodb2sqltexttotokenlist(); 4423 break; 4424 } 4425 case dbvteradata:{ 4426 doteradatatexttotokenlist(); 4427 break; 4428 } 4429 case dbvpostgresql:{ 4430 dopostgresqltexttotokenlist(); 4431 break; 4432 } 4433 case dbvredshift:{ 4434 doredshifttexttotokenlist(); 4435 break; 4436 } 4437 case dbvgreenplum:{ 4438 dogreenplumtexttotokenlist(); 4439 break; 4440 } 4441 case dbvmdx: { 4442 doMdxtexttotokenlist(); 4443 break; 4444 } 4445 case dbvnetezza:{ 4446 donetezzatexttotokenlist(); 4447 break; 4448 } 4449 case dbvhive:{ 4450 dohivetexttotokenlist(); 4451 break; 4452 } 4453 case dbvimpala:{ 4454 doimpalatexttotokenlist(); 4455 break; 4456 } 4457 case dbvmysql:{ 4458 domysqltexttotokenlist(); 4459 break; 4460 } 4461 case dbvhana:{ 4462 dohanasqltexttotokenlist(); 4463 break; 4464 } 4465 case dbvdax:{ 4466 dodaxsqltexttotokenlist(); 4467 break; 4468 } 4469 case dbvodbc:{ 4470 doodbcsqltexttotokenlist(); 4471 break; 4472 } 4473 case dbvvertica:{ 4474 doverticatexttotokenlist(); 4475 break; 4476 } 4477 case dbvopenedge:{ 4478 domssqlsqltexttotokenlist(); 4479 break; 4480 } 4481 case dbvcouchbase:{ 4482 docouchbasesqltexttotokenlist(); 4483 break; 4484 } 4485 case dbvsnowflake:{ 4486 dosnowflakesqltexttotokenlist(); 4487 break; 4488 } 4489 case dbvbigquery:{ 4490 dobigquerysqltexttotokenlist(); 4491 break; 4492 } 4493 case dbvclickhouse:{ 4494 doclickhousesqltexttotokenlist(); 4495 break; 4496 } 4497 case dbvsoql:{ 4498 dosoqlsqltexttotokenlist(); 4499 break; 4500 } 4501 case dbvsparksql:{ 4502 dosparksqltexttotokenlist(); 4503 break; 4504 } 4505 case dbvpresto:{ 4506 doprestotexttotokenlist(); 4507 break; 4508 } 4509 case dbvathena:{ 4510 doathenatexttotokenlist(); 4511 break; 4512 } 4513 case dbvdatabricks:{ 4514 dodatabrickstexttotokenlist(); 4515 break; 4516 } 4517 case dbvgaussdb:{ 4518 dogaussdbtexttotokenlist(); 4519 break; 4520 } 4521 case dbvansi:{ 4522 doansitexttotokenlist(); 4523 break; 4524 } 4525 default:{ 4526 docommonsqltexttotokenlist(); 4527 } 4528 } 4529 4530 doAfterTokenize(); 4531 4532 TBaseType.resetTokenChain(sourcetokenlist,0); 4533 4534 processTokensInTokenTable(dbVendor); 4535 processTokensBeforeParse(dbVendor); 4536 4537 closeFileStream(); 4538 4539 if (tokenListHandle != null){ 4540 tokenListHandle.processTokenList(sourcetokenlist); 4541 } 4542} 4543 4544void doAfterTokenize(){ 4545 4546 int leftParenCount = 0; 4547 int rightParenCount = 0; 4548 int leftIndex = 0; 4549 int rightIndex = sourcetokenlist.size() - 1; 4550 4551 // Count opening parentheses at the beginning 4552 while (leftIndex < sourcetokenlist.size() && sourcetokenlist.get(leftIndex).tokencode == '(') { 4553 leftParenCount++; 4554 leftIndex++; 4555 } 4556 4557 // Count closing parentheses at the end 4558 while (rightIndex >= 0 && sourcetokenlist.get(rightIndex).tokencode == ')') { 4559 rightParenCount++; 4560 rightIndex--; 4561 } 4562 4563 // Set matching parentheses to be ignored 4564 int parensToIgnore = Math.min(leftParenCount, rightParenCount); 4565 // if there is a semicolon before the right parenthesis, set the semicolon to be ignored 4566 // mantisbt/view.php?id=3690 4567 4568 if ((parensToIgnore > 0) && (sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokencode == ';')){ 4569 // set to whitespace that this semicolon will be ignored during getting raw sql 4570 sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokentype = ETokenType.ttwhitespace; 4571 // set to ignore by yacc that this semicolon will be ignored during parsing 4572 sourcetokenlist.get(sourcetokenlist.size() - 1 - (parensToIgnore - 1) - 1).tokenstatus = ETokenStatus.tsignorebyyacc; 4573 } 4574// for (int i = 0; i < parensToIgnore; i++) { 4575// //sourcetokenlist.get(i).tokenstatus = ETokenStatus.tsignorebyyacc; 4576// sourcetokenlist.get(i).tokencode = TBaseType.lexspace; 4577// 4578// // sourcetokenlist.get(sourcetokenlist.size() - 1 - i).tokenstatus = ETokenStatus.tsignorebyyacc; 4579// sourcetokenlist.get(sourcetokenlist.size() - 1 - i).tokencode = TBaseType.lexspace; 4580// } 4581 4582} 4583 4584 4585 4586void processTokensBeforeParse(EDbVendor dbVendor){ 4587 4588 // 为确保性能,只在snowflake数据库中处理,因为目前只有snowflake数据库中有连续的分号有用户提出这个需求,其他数据库中暂时不处理 4589 if (dbVendor != EDbVendor.dbvsnowflake) return; 4590 4591 // mantisbt/view.php?id=3579 4592 // if there are consecutive semicolon tokens, mark the second semi colon token as deleted token 4593 for(int i=0;i<sourcetokenlist.size();i++){ 4594 TSourceToken st = sourcetokenlist.get(i); 4595 if (st.tokencode == ';'){ 4596 TSourceToken nextToken = st.nextSolidToken(); 4597 if (nextToken != null){ 4598 if (nextToken.tokencode == ';'){ 4599 nextToken.tokenstatus = ETokenStatus.tsdeleted; 4600 } 4601 } 4602 } 4603 } 4604 4605} 4606 4607void processTokensInTokenTable(EDbVendor dbVendor){ 4608 // 获得所有token后,根据需要对token code进行预处理, token table是 TBaseType.TOKEN_TABLE 4609 long[][] TOKEN_TABLE1 = flexer.TOKEN_TABLE; 4610 4611 switch (dbVendor){ 4612 case dbvbigquery: 4613 case dbvsnowflake: 4614 // case 1, DO 关键字如果没有发现对于的 FOR, WHILE 等关键字,把 DO 关键字的token code设置为 TBaseType.ident 4615 4616 if (TOKEN_TABLE1[TBaseType.rrw_do][0] > 0){ 4617 if ((TOKEN_TABLE1[TBaseType.rrw_while][0] == 0)&&(TOKEN_TABLE1[TBaseType.rrw_for][0] == 0)){ 4618 for(int i=0;i<sourcetokenlist.size();i++){ 4619 TSourceToken st = sourcetokenlist.get(i); 4620 if (st.tokencode == TBaseType.rrw_do){ 4621 st.tokencode = TBaseType.ident; 4622 } 4623 } 4624 } 4625 } 4626 4627 break; 4628 } 4629 4630} 4631 4632boolean isDollarFunctionDelimiter(int tokencode, EDbVendor dbVendor){ 4633 return ((tokencode == TBaseType.rrw_postgresql_function_delimiter)&&(dbVendor == EDbVendor.dbvpostgresql)) 4634 ||((tokencode == TBaseType.rrw_greenplum_function_delimiter)&&(dbVendor == EDbVendor.dbvgreenplum)) 4635 ||((tokencode == TBaseType.rrw_redshift_function_delimiter)&&(dbVendor == EDbVendor.dbvredshift)) 4636 ||((tokencode == TBaseType.rrw_snowflake_function_delimiter)&&(dbVendor == EDbVendor.dbvsnowflake)) 4637 ||((tokencode == TBaseType.rrw_clickhouse_function_delimiter)&&(dbVendor == EDbVendor.dbvclickhouse)); 4638} 4639 4640/** 4641 * Returns the 1-based line number of the end of the last SQL statement that 4642 * was successfully recognized during raw-statement separation (e.g. via 4643 * vendor-specific {@code do*getrawsqlstatements} routines). 4644 * <p> 4645 * The value corresponds to the ending line of the last validated statement in 4646 * the most recent parse operation. Any trailing, incomplete statement at the 4647 * end of the input is intentionally excluded and will not affect this value. 4648 * <p> 4649 * Notes: 4650 * <ul> 4651 * <li>The line number is relative to the current input provided to the 4652 * parser (not an absolute position in an external, larger file).</li> 4653 * <li>This is useful when splitting huge SQL files by safe statement 4654 * boundaries — callers can cut the source at this line without risking a 4655 * partial statement.</li> 4656 * </ul> 4657 * 4658 * @return the 1-based line number of the last validated statement's ending 4659 * line, or {@code -1} if no statement has been validated yet 4660 */ 4661public int getLastLineNoOfLastStatementBeenValidated(){ 4662 if (lastTokenOfStatementBeenValidated != null){ 4663 return (int)lastTokenOfStatementBeenValidated.lineNo; 4664 } 4665 return -1; 4666} 4667 4668private TSourceToken lastTokenOfStatementBeenValidated; 4669 4670 4671void doongetrawsqlstatementevent(TCustomSqlStatement pcsqlstatement){ 4672 doongetrawsqlstatementevent(pcsqlstatement,false); 4673} 4674 4675void doongetrawsqlstatementevent(TCustomSqlStatement pcsqlstatement, boolean isLastSQL){ 4676 pcsqlstatement.setGsqlparser(this); 4677 pcsqlstatement.parser = this.fparser; 4678 pcsqlstatement.plsqlparser = this.fplsqlparser; 4679 pcsqlstatement.setStartToken(pcsqlstatement.sourcetokenlist.get(0)); 4680 pcsqlstatement.setEndToken(pcsqlstatement.sourcetokenlist.get(pcsqlstatement.sourcetokenlist.size()-1)); 4681 sqlstatements.add(pcsqlstatement); 4682 4683 if (!isLastSQL){ // 最后一个语句没有经过验证,只是在结束的时候强行加入的,很有可能是语法不正确的,因此我们这里只记录非最后的语句 4684 lastTokenOfStatementBeenValidated = pcsqlstatement.getEndToken(); 4685 } 4686 4687 // if stored procedure body is not written in sql or plsql, then, set the token in body to 4688 if ( ((this.dbVendor == EDbVendor.dbvpostgresql)||(this.dbVendor == EDbVendor.dbvgreenplum) ||(this.dbVendor == EDbVendor.dbvredshift) ||(this.dbVendor == EDbVendor.dbvsnowflake) ||(this.dbVendor == EDbVendor.dbvclickhouse) ) 4689 && (pcsqlstatement instanceof TRoutine) 4690 ){ 4691 if (!((TRoutine)pcsqlstatement).isBodyInSQL()){ 4692 TSourceToken st; 4693 boolean inBody = false; 4694 String routineBodyStr = ""; 4695 for(int i=0;i<pcsqlstatement.sourcetokenlist.size();i++){ 4696 st = pcsqlstatement.sourcetokenlist.get(i); 4697 if (isDollarFunctionDelimiter(st.tokencode,this.dbVendor) 4698// ((st.tokencode == TBaseType.rrw_postgresql_function_delimiter)&&(this.dbVendor == EDbVendor.dbvpostgresql)) 4699// ||((st.tokencode == TBaseType.rrw_greenplum_function_delimiter)&&(this.dbVendor == EDbVendor.dbvgreenplum)) 4700// ||((st.tokencode == TBaseType.rrw_redshift_function_delimiter)&&(this.dbVendor == EDbVendor.dbvredshift)) 4701// ||((st.tokencode == TBaseType.rrw_snowflake_function_delimiter)&&(this.dbVendor == EDbVendor.dbvsnowflake)) 4702 ){ 4703 if (!inBody){ 4704 inBody = true; 4705 routineBodyStr = st.toString(); 4706 }else{ 4707 inBody = false; 4708 routineBodyStr += st.toString(); 4709 break; 4710 } 4711 continue; 4712 } 4713 4714 if (inBody){ 4715 st.tokencode = TBaseType.sqlpluscmd; 4716 routineBodyStr += st.toString(); 4717 } 4718 } 4719 4720 ((TRoutine)pcsqlstatement).setRoutineBody(routineBodyStr); 4721 } 4722 } 4723} 4724 4725 int doclickhousegetrawsqlstatements(){ 4726 return dopostgresqlgetrawsqlstatements(); 4727 } 4728 4729 boolean checkTokenPairWithEnd(int tokencode){ 4730 return ((tokencode == TBaseType.rrw_if)||(tokencode == TBaseType.rrw_case) 4731 ||(tokencode == TBaseType.rrw_loop)||(tokencode == TBaseType.rrw_repeat) 4732 ||(tokencode == TBaseType.rrw_while)||(tokencode == TBaseType.rrw_for) 4733 ||(tokencode == TBaseType.rrw_case) 4734 ); 4735 } 4736 4737 int dopostgresqlgetrawsqlstatements(){ 4738 int waitingEnd = 0; 4739 boolean foundEnd = false, enterDeclare = false; 4740 4741 4742 4743 if ( TBaseType.assigned(sqlstatements) ) sqlstatements.clear(); 4744 if ( ! TBaseType.assigned(sourcetokenlist) ) return -1; 4745 4746 gcurrentsqlstatement = null; 4747 EFindSqlStateType gst = EFindSqlStateType.stnormal; 4748 TSourceToken lcprevsolidtoken = null,ast = null; 4749 4750 if (isSinglePLBlock){ 4751 gcurrentsqlstatement = new TCommonBlock(EDbVendor.dbvpostgresql); 4752 } 4753 4754 for (int i=0 ; i < sourcetokenlist.size();i++) 4755 { 4756 4757 if ( (ast != null ) && (ast.issolidtoken() )) 4758 lcprevsolidtoken = ast; 4759 4760 ast = sourcetokenlist.get(i); 4761 sourcetokenlist.curpos = i; 4762 if (isSinglePLBlock){ 4763 gcurrentsqlstatement.sourcetokenlist.add(ast); 4764 continue; 4765 } 4766 4767 if (ast.tokencode == TBaseType.JSON_EXIST){ 4768 TSourceToken stConstant = ast.searchToken(TBaseType.sconst,1); 4769 if (stConstant == null){ 4770 ast.tokencode = TBaseType.ident; 4771 } 4772 } 4773 else if (ast.tokencode == TBaseType.rrw_postgresql_POSITION) { 4774 TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1); 4775 if (st1 != null) { 4776 if (st1.tokencode == '(') { 4777 ast.tokencode = TBaseType.rrw_postgresql_POSITION_FUNCTION; 4778 } 4779 } 4780 }else if (ast.tokencode == TBaseType.rrw_postgresql_ordinality) { 4781 TSourceToken lcprevst = getprevsolidtoken(ast); 4782 4783 if (lcprevst != null) { 4784 if (lcprevst.tokencode == TBaseType.rrw_with) { 4785 TSourceToken lcnextst = ast.nextSolidToken(); 4786 if ((lcnextst != null)&&(lcnextst.tokencode == TBaseType.rrw_as)){ 4787 // with ordinality as (select 1 as x) select * from ordinality; 4788 // don't change with to rrw_postgresql_with_lookahead 4789 }else{ 4790 lcprevst.tokencode = TBaseType.rrw_postgresql_with_lookahead; 4791 } 4792 4793 } 4794 } 4795 } 4796 else if (ast.tokencode == TBaseType.rrw_postgresql_filter) { 4797 TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1); 4798 if (st1 != null) { 4799 if (st1.tokencode == '(') { 4800 4801 }else{ 4802 ast.tokencode = TBaseType.ident; 4803 } 4804 } 4805 } 4806 else if (ast.tokencode == TBaseType.rrw_postgresql_jsonb) { 4807 TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1); 4808 if (st1 != null) { 4809 if (st1.tokencode == '?') { 4810 st1.tokencode = TBaseType.OP_JSONB_QUESTION; 4811 } 4812 } 4813 } 4814 else if (ast.tokencode == '?') { 4815 TSourceToken st1 = ast.nextSolidToken(); //ast.searchToken('(',1); 4816 if (st1 != null) { 4817 if (st1.tokencode == TBaseType.sconst) { 4818 ast.tokencode = TBaseType.OP_JSONB_QUESTION; 4819 } 4820 } 4821 } 4822 else if (ast.tokencode == TBaseType.rrw_values) { 4823 TSourceToken stParen = ast.searchToken('(',1); 4824 if (stParen != null){ 4825 TSourceToken stInsert = ast.searchToken(TBaseType.rrw_insert,-ast.posinlist); 4826 if (stInsert != null){ 4827 TSourceToken stSemiColon = ast.searchToken(';',-ast.posinlist); 4828 if ((stSemiColon != null)&&(stSemiColon.posinlist > stInsert.posinlist)){ 4829// INSERT INTO test values (16,1), (8,2), (4,4), (2,0), (97, 16); 4830// VALUES (1); 4831 // don't treat values(1) as insert values 4832 4833 }else{ 4834 TSourceToken stFrom = ast.searchToken(TBaseType.rrw_from,-ast.posinlist); 4835 if ((stFrom != null)&&(stFrom.posinlist > stInsert.posinlist)){ 4836 // don't treat values after from keyword as an insert values 4837 4838 // insert into inserttest values(10, 20, '40'), (-1, 2, DEFAULT), ((select 2), (select i from (values(3) ) as foo (i)), 'values are fun!'); 4839 4840 }else{ 4841 ast.tokencode = TBaseType.rrw_postgresql_insert_values; 4842 } 4843 4844 } 4845 4846 } 4847 } 4848 } 4849 4850 switch(gst){ 4851 case sterror:{ 4852 if (ast.tokentype == ETokenType.ttsemicolon) 4853 { 4854 gcurrentsqlstatement.sourcetokenlist.add(ast); 4855 doongetrawsqlstatementevent(gcurrentsqlstatement); 4856 gst = EFindSqlStateType.stnormal; 4857 } 4858 else 4859 { 4860 gcurrentsqlstatement.sourcetokenlist.add(ast); 4861 } 4862 break; 4863 } //sterror 4864 4865 case stnormal:{ 4866 if ((ast.tokencode == TBaseType.cmtdoublehyphen) 4867 || (ast.tokencode == TBaseType.cmtslashstar) 4868 || (ast.tokencode == TBaseType.lexspace) 4869 || (ast.tokencode == TBaseType.lexnewline) 4870 || (ast.tokentype == ETokenType.ttsemicolon) ) 4871 { 4872 if (gcurrentsqlstatement != null) 4873 { 4874 gcurrentsqlstatement.addtokentolist(ast); 4875 } 4876 4877 if ((lcprevsolidtoken != null) && (ast.tokentype == ETokenType.ttsemicolon)) 4878 { 4879 if (lcprevsolidtoken.tokentype == ETokenType.ttsemicolon ) 4880 { 4881 // ;;;; continuous semicolon,treat it as comment 4882 ast.tokentype = ETokenType.ttsimplecomment; 4883 ast.tokencode = TBaseType.cmtdoublehyphen; 4884 } 4885 } 4886 4887 continue; 4888 } 4889 4890 if (ast.tokencode == TBaseType.sqlpluscmd ) 4891 { 4892 gst = EFindSqlStateType.stsqlplus; 4893 gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor); 4894 gcurrentsqlstatement.addtokentolist(ast); 4895 continue; 4896 } 4897 4898 // find a tokentext to start sql or plsql mode 4899 gcurrentsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement); 4900 4901 if (gcurrentsqlstatement != null) 4902 { 4903 enterDeclare = false; 4904 if (gcurrentsqlstatement.ispgplsql()) 4905 { 4906 gst = EFindSqlStateType.ststoredprocedure; 4907 gcurrentsqlstatement.addtokentolist(ast); 4908 foundEnd = false; 4909 if ((ast.tokencode == TBaseType.rrw_begin) 4910 ||(ast.tokencode == TBaseType.rrw_package) 4911 || (ast.searchToken(TBaseType.rrw_package,4) != null) 4912 ) 4913 { 4914 waitingEnd = 1; 4915 } 4916 else if (ast.tokencode == TBaseType.rrw_declare){ 4917 enterDeclare = true; 4918 } 4919 } 4920 else 4921 { 4922 gst = EFindSqlStateType.stsql; 4923 gcurrentsqlstatement.addtokentolist(ast); 4924 } 4925 }else{ 4926 //error tokentext found 4927 4928 this.syntaxErrors.add( new TSyntaxError(ast.getAstext(),ast.lineNo,(ast.columnNo < 0 ? 0:ast.columnNo) 4929 ,"Error when tokenlize", EErrorType.spwarning,TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE,null,ast.posinlist)); 4930 4931 ast.tokentype = ETokenType.tttokenlizererrortoken; 4932 gst = EFindSqlStateType.sterror; 4933 4934 gcurrentsqlstatement = new TUnknownSqlStatement(dbVendor); 4935 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 4936 gcurrentsqlstatement.addtokentolist(ast); 4937 4938 } 4939 4940 break; 4941 } // stnormal 4942 4943 case stsqlplus:{ 4944 if (ast.insqlpluscmd) 4945 {gcurrentsqlstatement.addtokentolist(ast);} 4946 else 4947 { 4948 gst = EFindSqlStateType.stnormal; //this tokentext must be newline, 4949 gcurrentsqlstatement.addtokentolist(ast); // so add it here 4950 doongetrawsqlstatementevent(gcurrentsqlstatement); 4951 } 4952 4953 break; 4954 }//case stsqlplus 4955 4956 case stsql:{ 4957 if (ast.tokentype == ETokenType.ttsemicolon) 4958 { 4959 gst = EFindSqlStateType.stnormal; 4960 gcurrentsqlstatement.addtokentolist(ast); 4961 gcurrentsqlstatement.semicolonended = ast; 4962 doongetrawsqlstatementevent(gcurrentsqlstatement); 4963 continue; 4964 } 4965 4966 if (sourcetokenlist.sqlplusaftercurtoken() ) //most probaly is / cmd 4967 { 4968 gst = EFindSqlStateType.stnormal; 4969 gcurrentsqlstatement.addtokentolist(ast); 4970 doongetrawsqlstatementevent(gcurrentsqlstatement); 4971 continue; 4972 } 4973 4974 if (ast.tokencode == TBaseType.cmtdoublehyphen){ 4975 if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter 4976 gst = EFindSqlStateType.stnormal; 4977 doongetrawsqlstatementevent(gcurrentsqlstatement); 4978 continue; 4979 } 4980 } 4981 4982 gcurrentsqlstatement.addtokentolist(ast); 4983 break; 4984 }//case stsql 4985 4986 case ststoredprocedure:{ 4987 if (ast.tokencode == TBaseType.rrw_postgresql_function_delimiter){ 4988 gcurrentsqlstatement.addtokentolist(ast); 4989 gst = EFindSqlStateType.ststoredprocedurePgStartBody; 4990 4991 continue; 4992 } 4993 4994 if (ast.tokencode == TBaseType.rrw_postgresql_language){ 4995 // check next token which is the language used by this stored procedure 4996 TSourceToken nextSt = ast.nextSolidToken(); 4997 if (nextSt != null){ 4998 if (gcurrentsqlstatement instanceof TRoutine){ // can be TCreateProcedureStmt or TCreateFunctionStmt 4999 TRoutine p = (TRoutine) gcurrentsqlstatement; 5000 p.setRoutineLanguage(nextSt.toString()); 5001 } 5002 } 5003 } 5004 5005 if ((ast.tokentype == ETokenType.ttsemicolon) && (waitingEnd == 0) && (!enterDeclare)) 5006 { 5007 gst = EFindSqlStateType.stnormal; 5008 gcurrentsqlstatement.addtokentolist(ast); 5009 gcurrentsqlstatement.semicolonended = ast; 5010 doongetrawsqlstatementevent(gcurrentsqlstatement); 5011 continue; 5012 } 5013 5014 if ((ast.tokencode == TBaseType.rrw_begin) 5015 //||(ast.tokencode == TBaseType.rrw_between) 5016 ) 5017 { 5018 waitingEnd++; 5019 enterDeclare = false; 5020 } 5021 else if ( 5022 (ast.tokencode == TBaseType.rrw_declare) 5023 ){ 5024 enterDeclare = true; 5025 } 5026 else if ( 5027 (ast.tokencode == TBaseType.rrw_if) 5028 ){ 5029 if (ast.searchToken(TBaseType.rrw_end,-1) == null){ 5030 //this is not if after END 5031 waitingEnd++; 5032 } 5033 } 5034 else if ( 5035 (ast.tokencode == TBaseType.rrw_case) 5036 ){ 5037 if (ast.searchToken(TBaseType.rrw_end,-1) == null){ 5038 //this is not case after END 5039 waitingEnd++; 5040 } 5041 } 5042 else if ( 5043 (ast.tokencode == TBaseType.rrw_loop) 5044 ){ 5045 if (ast.searchToken(TBaseType.rrw_end,-1) == null){ 5046 //this is not loop after END 5047 waitingEnd++; 5048 } 5049 } 5050 else if (ast.tokencode == TBaseType.rrw_end){ 5051 foundEnd = true; 5052 waitingEnd--; 5053 if (waitingEnd < 0) { waitingEnd = 0;} 5054 } 5055 5056 if ((ast.tokentype == ETokenType.ttslash) && (ast.tokencode == TBaseType.sqlpluscmd) ) //and (prevst.NewlineIsLastTokenInTailerToken)) then 5057 { 5058 // TPlsqlStatementParse(asqlstatement).TerminatorToken := ast; 5059 ast.tokenstatus = ETokenStatus.tsignorebyyacc; 5060 gst = EFindSqlStateType.stnormal; 5061 doongetrawsqlstatementevent(gcurrentsqlstatement); 5062 5063 //make / a sqlplus cmd 5064 gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor); 5065 gcurrentsqlstatement.addtokentolist(ast); 5066 doongetrawsqlstatementevent(gcurrentsqlstatement); 5067 } 5068 else if ((ast.tokentype == ETokenType.ttperiod) && (sourcetokenlist.returnaftercurtoken(false)) && (sourcetokenlist.returnbeforecurtoken(false))) 5069 { // single dot at a seperate line 5070 ast.tokenstatus = ETokenStatus.tsignorebyyacc; 5071 gst = EFindSqlStateType.stnormal; 5072 doongetrawsqlstatementevent(gcurrentsqlstatement); 5073 5074 //make ttperiod a sqlplus cmd 5075 gcurrentsqlstatement = new TSqlplusCmdStatement(dbVendor); 5076 gcurrentsqlstatement.addtokentolist(ast); 5077 doongetrawsqlstatementevent(gcurrentsqlstatement); 5078 } 5079 else 5080 { 5081 gcurrentsqlstatement.addtokentolist(ast); 5082 if ((ast.tokentype == ETokenType.ttsemicolon) && (waitingEnd == 0) 5083 && (foundEnd) 5084 // && (gcurrentsqlstatement.OracleStatementCanBeSeparatedByBeginEndPair()) 5085 ){ 5086 gst = EFindSqlStateType.stnormal; 5087 doongetrawsqlstatementevent(gcurrentsqlstatement); 5088 } 5089 } 5090 5091 if (ast.tokencode == TBaseType.sqlpluscmd) 5092 { 5093 //change tokencode back to keyword or TBaseType.ident, because sqlplus cmd 5094 //in a sql statement(almost is plsql block) is not really a sqlplus cmd 5095 int m = flexer.getkeywordvalue(ast.getAstext()); 5096 if (m != 0) 5097 {ast.tokencode = m;} 5098 else 5099 {ast.tokencode = TBaseType.ident;} 5100 } 5101 5102 if (( gst == EFindSqlStateType.ststoredprocedure ) && (ast.tokencode == TBaseType.cmtdoublehyphen)){ 5103 if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter 5104 gst = EFindSqlStateType.stnormal; 5105 doongetrawsqlstatementevent(gcurrentsqlstatement); 5106 } 5107 } 5108 5109 break; 5110 } //ststoredprocedure 5111 5112 case ststoredprocedurePgStartBody:{ 5113 gcurrentsqlstatement.addtokentolist(ast); 5114 5115 if (ast.tokencode == TBaseType.rrw_postgresql_function_delimiter){ 5116 if (gcurrentsqlstatement.sqlstatementtype == sstDoExecuteBlock){ 5117 gst = EFindSqlStateType.stnormal; 5118 doongetrawsqlstatementevent(gcurrentsqlstatement); 5119 continue; 5120 5121 }else{ 5122 gst = EFindSqlStateType.ststoredprocedurePgEndBody; 5123 continue; 5124 } 5125 } 5126 5127 break; 5128 } 5129 5130 case ststoredprocedurePgEndBody:{ 5131 5132 if (ast.tokentype == ETokenType.ttsemicolon) 5133 { 5134 gst = EFindSqlStateType.stnormal; 5135 gcurrentsqlstatement.addtokentolist(ast); 5136 gcurrentsqlstatement.semicolonended = ast; 5137 doongetrawsqlstatementevent(gcurrentsqlstatement); 5138 continue; 5139 } 5140 else if (ast.tokencode == TBaseType.cmtdoublehyphen){ 5141 if (ast.toString().trim().endsWith(TBaseType.sqlflow_stmt_delimiter_str)){ // -- sqlflow-delimiter 5142 gst = EFindSqlStateType.stnormal; 5143 doongetrawsqlstatementevent(gcurrentsqlstatement); 5144 continue; 5145 } 5146 } 5147 5148 gcurrentsqlstatement.addtokentolist(ast); 5149 5150 if (ast.tokencode == TBaseType.rrw_postgresql_language){ 5151 // check next token which is the language used by this stored procedure 5152 TSourceToken nextSt = ast.nextSolidToken(); 5153 if (nextSt != null){ 5154 if (gcurrentsqlstatement instanceof TRoutine){ // can be TCreateProcedureStmt or TCreateFunctionStmt 5155 TRoutine p = (TRoutine) gcurrentsqlstatement; 5156 p.setRoutineLanguage(nextSt.toString()); 5157 } 5158 } 5159 } 5160 5161 break; 5162 } 5163 } //switch 5164 }//for 5165 5166 //last statement 5167 if ((gcurrentsqlstatement != null) && 5168 ((gst == EFindSqlStateType.stsqlplus) || (gst == EFindSqlStateType.stsql) 5169 || (gst == EFindSqlStateType.ststoredprocedure) 5170 || (gst == EFindSqlStateType.ststoredprocedurePgEndBody) 5171 ||(gst == EFindSqlStateType.sterror)||(isSinglePLBlock) 5172 )) 5173 { 5174 doongetrawsqlstatementevent(gcurrentsqlstatement,true); 5175 } 5176 5177 return syntaxErrors.size(); 5178 } 5179 5180 /** 5181 * Functionality 5182 * Target Identification: 5183 * Scans for CREATE PROCEDURE and CREATE FUNCTION statements 5184 * Verifies the language is SQL (for procedures) 5185 * Identifies dollar-quoted strings ($$...$$) and single-quoted strings after AS keywords 5186 * Token Expansion: 5187 * For each identified string literal: 5188 * Extracts the content between the quotes 5189 * Tokenizes the extracted SQL code 5190 * Verifies it's a valid code block (starts with DECLARE or BEGIN) 5191 * Replaces the original quoted string with expanded tokens in the source token list 5192 * Special Transformations: 5193 * Converts BEGIN; to BEGIN TRANSACTION; 5194 * Handles BEGIN WORK; similarly 5195 * Special handling for semicolons after END statements 5196 * Token Chain Management: 5197 * Preserves original quotes as space tokens 5198 * Maintains proper token positioning and chaining 5199 * Resets the token chain to ensure correct output during toString() operations 5200 * Implementation Details 5201 * Processes statements in reverse order to maintain correct token positions 5202 * Uses TBaseType.getStringInsideLiteral() to extract content between quotes 5203 * Marks original dollar-quoted tokens as deleted (using tsdeleted) 5204 * Handles multi-line SQL blocks within stored procedure/function bodies 5205 */ 5206 void expandDollarString(){ 5207 // snowflake, expand dollar string into token list 5208 TSourceToken st; 5209 TCustomSqlStatement sql; 5210 ArrayList<TSourceToken> dollarTokens = new ArrayList<>(); 5211 boolean isSQLLanguage = true; 5212 5213 // Iterate all create procedure and create function, other sql staetment just skipped 5214 for(int i=0;i<sqlstatements.size();i++){ 5215 sql = sqlstatements.get(i); 5216 if (!((sql.sqlstatementtype == sstcreateprocedure)||(sql.sqlstatementtype == sstcreatefunction))) continue; 5217 isSQLLanguage = true; 5218 for(int j=0;j<sql.sourcetokenlist.size();j++){ 5219 st = sql.sourcetokenlist.get(j); 5220 5221 if (sql.sqlstatementtype == sstcreateprocedure){ 5222 if (st.tokencode == TBaseType.rrw_snowflake_language){ 5223 TSourceToken lang = st.nextSolidToken(); 5224 if ((lang != null)&&(!lang.toString().equalsIgnoreCase("sql"))){ 5225 isSQLLanguage = false; 5226 } 5227 } 5228 } 5229 5230 if (!isSQLLanguage) break; 5231 5232 if (st.tokencode == TBaseType.sconst){ 5233 if (st.toString().startsWith("$$")){ 5234 dollarTokens.add(st); // TODO: 可能会有多个 $$ token? 这种情况再哪个场景下会出现?需要找到对应的测试用例和SQL脚本。否则,uncomment next line 5235 // break; // only one $$ token per sql, if we found one, then just break this sql and continue for next sql 5236 }else if (st.toString().startsWith("'")){ 5237 // https://docs.snowflake.com/en/sql-reference/sql/create-procedure 5238 // string literal delimiter can be $ or ' 5239 if (st.prevSolidToken().tokencode == TBaseType.rrw_as){ 5240 dollarTokens.add(st); // TODO: 可能会有多个 $$ token? 这种情况再哪个场景下会出现?需要找到对应的测试用例和SQL脚本。否则,uncomment next line 5241 // break; // only one single quote token per sql, if we found one, then just break this sql and continue for next sql 5242 } 5243 } 5244 } 5245 }//check tokens 5246 5247 for(int m= dollarTokens.size() - 1; m>=0;m--){ 5248 5249 // Token Expansion: 5250 // For each identified string literal: 5251 // Extracts the content between the quotes 5252 // Tokenizes the extracted SQL code 5253 // Verifies it's a valid code block (starts with DECLARE or BEGIN) 5254 // Replaces the original quoted string with expanded tokens in the source token list 5255 5256 st = dollarTokens.get(m); 5257 5258 TGSqlParser parser = new TGSqlParser(this.dbVendor); 5259 //parser.sqltext = TBaseType.stringBlock((int)st.lineNo - 1,(int)st.columnNo)+ TBaseType.getStringInsideLiteral(st.toString()); 5260 // 如果在前面补充空行,会导致 toString() 重新拼接时多出空行; 5261 // 同时,因为不需要进行解析,所以不需要在前面补充空行以获得准确的错误定位? 这个说法是错误的,因为不加需要的空行,会导致定位不准确 #TODO 5262 parser.sqltext = TBaseType.getStringInsideLiteral(st.toString()); 5263 TSourceToken startQuote = new TSourceToken(st.toString().substring(0,1)); 5264 startQuote.tokencode = TBaseType.lexspace; // 设置为 space,可以在解析时忽略该token,同时在 toString() 时会被原样输出 5265 TSourceToken endQuote = new TSourceToken(st.toString().substring(0,1)); 5266 endQuote.tokencode = TBaseType.lexspace; 5267 5268 // use getrawsqlstatements() instead of tokenizeSqltext() to get the source token list because 5269 // some token will be transformed to other token, which will be processed in dosnowflakegetrawsqlstatements() 5270 parser.getrawsqlstatements(); 5271 //parser.tokenizeSqltext(); 5272 5273 TSourceToken st2; 5274 boolean isValidBlock = false; 5275 for(int k=0;k<parser.sourcetokenlist.size();k++){ 5276 st2 = parser.sourcetokenlist.get(k); 5277 if (st2.isnonsolidtoken()) continue; 5278 if ((st2.tokencode == TBaseType.rrw_declare)||(st2.tokencode == TBaseType.rrw_begin)){ 5279 isValidBlock = true; 5280 }else{ 5281 // 5282 } 5283 break; 5284 //System.out.println(st2.lineNo+","+st2.columnNo+":"+st2.toString()); 5285 } 5286 5287 if (isValidBlock){ 5288 TSourceToken semiColon = null; 5289 st.tokenstatus = ETokenStatus.tsdeleted; 5290 int startPosOfThisSQl = sql.getStartToken().posinlist; 5291 5292 sql.sourcetokenlist.add((st.posinlist++) - startPosOfThisSQl,startQuote); // 补上开始引号 5293 for(int k=0;k<parser.sourcetokenlist.size();k++) { 5294 st2 = parser.sourcetokenlist.get(k); 5295 if (st2.tokencode == ';'){ 5296 semiColon = st2; 5297 TSourceToken prevSolidToken = st2.prevSolidToken(); 5298 if ((prevSolidToken != null) && (prevSolidToken.tokencode == TBaseType.rrw_begin)){ 5299 // begin; => begin transaction; 5300 prevSolidToken.tokencode = TBaseType.rrw_snowflake_begin_transaction; 5301 } 5302 } 5303 if ((st2.tokencode == TBaseType.rrw_snowflake_work)||(st2.tokencode == TBaseType.rrw_snowflake_transaction)){ 5304 // begin work; => begin transaction; 5305 TSourceToken prevSolidToken = st2.prevSolidToken(); 5306 if ((prevSolidToken != null) && (prevSolidToken.tokencode == TBaseType.rrw_begin)){ 5307 // begin; => begin transaction; 5308 prevSolidToken.tokencode = TBaseType.rrw_snowflake_begin_transaction; 5309 } 5310 } 5311 sql.sourcetokenlist.add( (st.posinlist++) - startPosOfThisSQl,st2); 5312 //st.posinlist++; 5313 } 5314 if (semiColon != null){ 5315 if (semiColon.prevSolidToken().tokencode == TBaseType.rrw_end){ 5316 // 设置为 space,可以在解析时忽略该token,同时在 toString() 时会被原样输出 5317 // semiColon.tokenstatus = ETokenStatus.tsdeleted; 5318 semiColon.tokencode = TBaseType.lexspace; 5319 } 5320 } 5321 5322 sql.sourcetokenlist.add( (st.posinlist++) - startPosOfThisSQl,endQuote); // 补上结束引号 5323 TBaseType.resetTokenChain(sql.sourcetokenlist,0); // 重新设置token链,确保新插入的token在 toString() 时能被访问到,从而确保 toString() 输出正确结果 5324 } 5325 } 5326 5327 dollarTokens.clear(); 5328 }//statement 5329 5330 } 5331 5332 int domssqlgetrawsqlstatements(){ 5333 5334 // Original implementation follows... 5335 int errorcount = 0; 5336 int case_end_nest = 0; 5337 5338 if ( TBaseType.assigned(sqlstatements) ) sqlstatements.clear(); 5339 if ( ! TBaseType.assigned(sourcetokenlist) ) return -1; 5340 5341 gcurrentsqlstatement = null; 5342 EFindSqlStateType gst = EFindSqlStateType.stnormal; 5343 int lcblocklevel = 0; 5344 int lctrycatchlevel = 0; 5345 TSourceToken lcprevsolidtoken = null,lcnextsolidtoken,lcnnextsolidtoken; 5346 TSourceToken ast = null; 5347 int i,lcMergeInSelectNested = 0; 5348 boolean lcisendconversation, lcstillinsql,lcMergeInSelect = false; 5349 5350 for (i=0 ; i < sourcetokenlist.size();i++) 5351 { 5352 5353 if ( (ast != null ) && (ast.issolidtoken() )) 5354 lcprevsolidtoken = ast; 5355 5356 ast = sourcetokenlist.get(i); 5357 sourcetokenlist.curpos = i; 5358 5359 if (ast.tokencode == TBaseType.rrw_for){ 5360 TSourceToken st1 = ast.nextSolidToken(); 5361 if ((st1 != null) && (st1.tokencode == TBaseType.rrw_system_time)){ 5362 ast.tokencode = TBaseType.rw_for_system_time; 5363 } 5364 } 5365 5366 if (lcMergeInSelect){ 5367 if (ast.tokencode == '(') lcMergeInSelectNested++; 5368 if (ast.tokencode == ')'){ 5369 lcMergeInSelectNested--; 5370 if (lcMergeInSelectNested == 0){ 5371 lcMergeInSelect = false; 5372 } 5373 } 5374 gcurrentsqlstatement.sourcetokenlist.add(ast); 5375 continue; 5376 } 5377 if ( ast.tokenstatus == ETokenStatus.tsignoredbygetrawstatement ) 5378 { 5379 //tsignoredbygetrawstatement is set when cte is found in dbcmds.findcte function 5380 gcurrentsqlstatement.sourcetokenlist.add(ast); 5381 continue; 5382 } 5383 5384 if (ast.tokencode == TBaseType.rrw_minus){ 5385 TSourceToken st1 = ast.searchToken('(',1); 5386 if (st1 == null){ 5387 st1 = ast.searchToken(TBaseType.rrw_select,1); 5388 if (st1 == null){ 5389 ast.tokencode = TBaseType.ident; 5390 } 5391 } 5392 }else if (ast.tokencode == TBaseType.rrw_merge){ 5393 TSourceToken st1 = ast.nextSolidToken(); 5394 if (st1.tokencode == TBaseType.rrw_join){ 5395 ast.tokencode = TBaseType.rrw_merge2_sqlserver; 5396 } 5397 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '(')){ 5398 lcMergeInSelect = true; 5399 lcMergeInSelectNested++; 5400 gcurrentsqlstatement.addtokentolist(ast); 5401 continue; 5402 } 5403 }else if (ast.tokencode == TBaseType.rrw_sqlserver_value){ 5404 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){ 5405 TSourceToken st1 = ast.searchToken('(',1); 5406 if (st1 != null) { 5407 ast.tokencode = TBaseType.rrw_xml_value; 5408 } 5409 } 5410 }else if (ast.tokencode == TBaseType.rrw_sqlserver_modify){ 5411 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){ 5412 TSourceToken st1 = ast.searchToken('(',1); 5413 if (st1 != null) { 5414 ast.tokencode = TBaseType.rrw_xml_modify; 5415 } 5416 } 5417 }else if (ast.tokencode == TBaseType.rrw_sqlserver_query){ 5418 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){ 5419 TSourceToken st1 = ast.searchToken('(',1); 5420 if (st1 != null) { 5421 ast.tokencode = TBaseType.rrw_xml_query; 5422 } 5423 } 5424 }else if (ast.tokencode == TBaseType.rrw_sqlserver_exist){ 5425 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){ 5426 TSourceToken st1 = ast.searchToken('(',1); 5427 if (st1 != null) { 5428 ast.tokencode = TBaseType.rrw_xml_exist; 5429 } 5430 } 5431 }else if (ast.tokencode == TBaseType.rrw_sqlserver_nodes){ 5432 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == '.')){ 5433 TSourceToken st1 = ast.searchToken('(',1); 5434 if (st1 != null) { 5435 ast.tokencode = TBaseType.rrw_xml_nodes; 5436 } 5437 } 5438 }else if (ast.tokencode == TBaseType.rrw_check){ 5439 if ((lcprevsolidtoken != null)&&(lcprevsolidtoken.tokencode == TBaseType.rrw_with)){ 5440 lcprevsolidtoken.tokencode = TBaseType.rrw_sqlserver_check_with; 5441 } 5442// }else if (ast.tokencode == TBaseType.rrw_for){ 5443// TSourceToken st1 = ast.nextSolidToken(); 5444// if ((st1 != null) && (st1.tokencode == TBaseType.rrw_system_time)){ 5445// ast.tokencode = TBaseType.rw_for_system_time; 5446// } 5447 }else if (ast.tokencode == TBaseType.rrw_sqlserver_next){ 5448 TSourceToken st1 = ast.nextSolidToken(); 5449 if ((st1 != null) && (st1.tokencode == '.')){ 5450 ast.tokencode = TBaseType.ident; 5451 } 5452 }else if (ast.tokencode == TBaseType.rrw_fetch){ 5453 if ((lcprevsolidtoken != null)&&((lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_row)||(lcprevsolidtoken.tokencode == TBaseType.rrw_sqlserver_rows))){ 5454 TSourceToken prev2 = lcprevsolidtoken.searchToken(TBaseType.rrw_open,-1); 5455 if (prev2 == null){ 5456 ast.tokencode = TBaseType.rrw_sqlserver_offset_fetch; 5457 }else{ 5458 // don't turn fetch to TBaseType.rrw_sqlserver_offset_fetch 5459 //open row 5460 //fetch row into @msg 5461 } 5462 5463 } 5464 }else if((ast.tokencode == TBaseType.rrw_exec)||(ast.tokencode == TBaseType.rrw_execute)){ 5465 // search ;2 after execute 5466 // EXECUTE ApxSQL_Test_Triggers_Add;2 @TableName, @AddFlag 5467 int searchRange = 4; 5468 TSourceToken endTokenInSameLine = ast.searchTokenAtTheEndOfSameLine(); 5469 if (endTokenInSameLine != null){ 5470 searchRange = endTokenInSameLine.posinlist - ast.posinlist; 5471 } 5472 TSourceToken st1 = ast.searchToken(';',searchRange); 5473 if (st1 != null){ 5474 TSourceToken numSt = st1.nextSolidToken(); 5475 if ((numSt != null)&&(numSt.tokentype == ETokenType.ttnumber)){ 5476 st1.tokencode = TBaseType.rrw_sqlserver_semicolon_module_number; 5477 st1.tokentype = ETokenType.ttidentifier; 5478 } 5479 } 5480 } 5481 else if (ast.tokencode == TBaseType.rrw_sqlserver_trim){ 5482 TSourceToken st1 = ast.nextSolidToken(); 5483 if (st1 != null){ 5484 if (st1.tokencode == '('){ 5485 5486 }else{ 5487 ast.tokencode = TBaseType.ident; // change trim keyword to identifier if not followed by (), trim() 5488 } 5489 } 5490 } 5491 5492 if (dbVendor == EDbVendor.dbvopenedge){ 5493 if (ast.tokencode == TBaseType.rrw_order){ 5494 TSourceToken st1 = ast.searchToken(TBaseType.rrw_by,1); 5495 if (st1 == null) { 5496 ast.tokencode = TBaseType.ident; 5497 } 5498 }else if (ast.tokencode == TBaseType.rrw_with){ 5499 TSourceToken st1 = ast.searchToken(TBaseType.rrw_check,1); 5500 if (st1 != null) { 5501 ast.tokencode = TBaseType.rrw_openedge_with_check; 5502 } 5503 } 5504 } 5505 5506 if ( gst == EFindSqlStateType.ststoredprocedurebody ) 5507 { 5508 if ( !( 5509 (ast.tokencode == TBaseType.rrw_go) 5510 || (ast.tokencode == TBaseType.rrw_create) 5511 || (ast.tokencode == TBaseType.rrw_alter) ) 5512 ) 5513 { 5514 gcurrentsqlstatement.sourcetokenlist.add(ast); 5515 continue; 5516 } 5517 } 5518 5519 TCustomSqlStatement lcnextsqlstatement = sqlcmds.issql(ast, gst, gcurrentsqlstatement); 5520 5521 switch(gst){ 5522 case sterror: 5523 { 5524 if ( TBaseType.assigned(lcnextsqlstatement) ) 5525 { 5526 doongetrawsqlstatementevent(gcurrentsqlstatement); 5527 gcurrentsqlstatement = lcnextsqlstatement; 5528 gcurrentsqlstatement.sourcetokenlist.add(ast); 5529 gst = EFindSqlStateType.stsql; 5530 } 5531 else if ( (ast.tokentype == ETokenType.ttsemicolon) ) 5532 { 5533 gcurrentsqlstatement.sourcetokenlist.add(ast); 5534 doongetrawsqlstatementevent(gcurrentsqlstatement); 5535 gst = EFindSqlStateType.stnormal; 5536 } 5537 else 5538 { 5539 gcurrentsqlstatement.sourcetokenlist.add(ast); 5540 } 5541 break; 5542 } 5543 case stnormal : 5544 { 5545 if ( (ast.tokencode == TBaseType.cmtdoublehyphen) 5546 || (ast.tokencode == TBaseType.cmtslashstar) 5547 || (ast.tokencode == TBaseType.lexspace) 5548 || (ast.tokencode == TBaseType.lexnewline) 5549 || (ast.tokentype == ETokenType.ttsemicolon) ) 5550 { 5551 if ( TBaseType.assigned(gcurrentsqlstatement) ) 5552 { 5553 gcurrentsqlstatement.addtokentolist(ast); 5554 } 5555 5556 if ( TBaseType.assigned(lcprevsolidtoken) && (ast.tokentype == ETokenType.ttsemicolon) ) 5557 { 5558 if ( lcprevsolidtoken.tokentype == ETokenType.ttsemicolon ) 5559 { 5560 // ;;;; continuous semicolon,treat it as comment 5561 ast.tokentype = ETokenType.ttsimplecomment; 5562 ast.tokencode = TBaseType.cmtdoublehyphen; 5563 } 5564 else 5565 { 5566 } 5567 5568 } 5569 5570 continue; 5571 } 5572 5573 gcurrentsqlstatement = lcnextsqlstatement; //isstoredprocedure(ast,dbvendor,gst,sqlstatements); 5574 5575 if ( TBaseType.assigned(gcurrentsqlstatement) ) 5576 { 5577 switch(gcurrentsqlstatement.sqlstatementtype){ // 5578 case sstmssqlcreateprocedure: 5579 case sstmssqlcreatefunction: 5580 //case sstmssqlcreatetrigger: 5581 case sstcreatetrigger: 5582 case sstmssqlalterprocedure: 5583 case sstmssqlalterfunction: 5584 case sstmssqlaltertrigger: 5585 { 5586 gcurrentsqlstatement.addtokentolist(ast); 5587 gst = EFindSqlStateType.ststoredprocedure; 5588 break; 5589 } 5590 case sstmssqlbegintry: 5591 case sstmssqlbegincatch: 5592 { 5593 gcurrentsqlstatement.addtokentolist(ast); 5594 gst = EFindSqlStateType.sttrycatch; 5595 lctrycatchlevel = 0; 5596 break; 5597 } 5598 case sstmssqlgo: 5599 { 5600 gcurrentsqlstatement.addtokentolist(ast); 5601 doongetrawsqlstatementevent(gcurrentsqlstatement); 5602 gst = EFindSqlStateType.stnormal; 5603 break; 5604 } 5605 default: 5606 { 5607 gcurrentsqlstatement.addtokentolist(ast); 5608 gst = EFindSqlStateType.stsql; 5609 break; 5610 } 5611 } // case 5612 } 5613 else 5614 { 5615 if ( ast.tokencode == TBaseType.rrw_begin ) 5616 { 5617 gcurrentsqlstatement = new TMssqlBlock(dbVendor); 5618 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 5619 gcurrentsqlstatement.addtokentolist(ast); 5620 gst = EFindSqlStateType.stblock; 5621 } 5622 else 5623 { 5624 if ( sqlstatements.size() == 0 ) 5625 { 5626 //first statement of mssql batch, treat it as exec sp 5627 gst = EFindSqlStateType.stsql; 5628 gcurrentsqlstatement = new TMssqlExecute(dbVendor); 5629 //tmssqlexecute(gcurrentsqlstatement).exectype = metnoexeckeyword; 5630// todo need previous line need to be implemented 5631 gcurrentsqlstatement.addtokentolist(ast); 5632 } 5633 else if ( sqlstatements.get(sqlstatements.size() -1).sqlstatementtype == ESqlStatementType.sstmssqlgo ) 5634 { 5635 // prev sql is go, treat it as exec sp 5636 gst = EFindSqlStateType.stsql; 5637 gcurrentsqlstatement = new TMssqlExecute(dbVendor); 5638 //todo need to be implemented: tmssqlexecute(gcurrentsqlstatement).exectype = metnoexeckeyword; 5639 gcurrentsqlstatement.addtokentolist(ast); 5640 } 5641 else 5642 { 5643 } 5644 } 5645 } 5646 5647 5648 if ( !TBaseType.assigned(gcurrentsqlstatement) ) //error tokentext found 5649 { 5650 5651 5652 this.syntaxErrors.add( new TSyntaxError(ast.getAstext(),ast.lineNo,(ast.columnNo < 0 ? 0:ast.columnNo) 5653 ,"Error when tokenlize", EErrorType.spwarning,TBaseType.MSG_WARNING_ERROR_WHEN_TOKENIZE,null,ast.posinlist)); 5654 5655 5656 ast.tokentype = ETokenType.tttokenlizererrortoken; 5657 gst = EFindSqlStateType.sterror; 5658 5659 gcurrentsqlstatement = new TUnknownSqlStatement(dbVendor); 5660 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstinvalid; 5661 gcurrentsqlstatement.addtokentolist(ast); 5662 } 5663 break; 5664 } 5665 case stblock: 5666 { 5667 if ( TBaseType.assigned(lcnextsqlstatement) ) 5668 { 5669 if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo ) 5670 { 5671 doongetrawsqlstatementevent(gcurrentsqlstatement); 5672 gcurrentsqlstatement = lcnextsqlstatement; 5673 gcurrentsqlstatement.addtokentolist(ast); 5674 doongetrawsqlstatementevent(gcurrentsqlstatement); 5675 gst = EFindSqlStateType.stnormal; 5676 } 5677 else 5678 { 5679 lcnextsqlstatement = null; 5680 } 5681 } 5682 5683 if ( gst == EFindSqlStateType.stblock ) 5684 { 5685 gcurrentsqlstatement.addtokentolist(ast); 5686 if ( ast.tokencode == TBaseType.rrw_begin ) 5687 { 5688 // { [distributed] transaxtion/trans statement 5689 // { dialog [ conversation ] 5690 // { conversation timer 5691 // doesn't start block ({ .. }) 5692 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false); 5693 if ( TBaseType.assigned(lcnextsolidtoken) ) 5694 { 5695 if ( ! ( (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_tran) 5696 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_transaction) 5697 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_distributed) 5698 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_dialog) 5699 || (lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 5700 ) ) 5701 lcblocklevel++; 5702 } 5703 else 5704 lcblocklevel++; 5705 5706 } 5707 else if ( ast.tokencode == TBaseType.rrw_case ) // case ... } 5708 lcblocklevel++; 5709 else if ( ast.tokencode == TBaseType.rrw_end ) 5710 { 5711 5712 lcisendconversation = false; 5713 5714 5715 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false); 5716 if ( TBaseType.assigned(lcnextsolidtoken) ) 5717 { 5718 if ( lcnextsolidtoken.tokencode == TBaseType.rrw_sqlserver_conversation) 5719 lcisendconversation = true; // } conversation statement 5720 } 5721 5722 5723 if ( ! lcisendconversation ) 5724 { 5725 5726 if ( lcblocklevel == 0 ) 5727 { 5728 if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif ) 5729 { 5730 if ( TBaseType.assigned(lcnextsolidtoken) ) 5731 { 5732 if ( lcnextsolidtoken.tokencode == TBaseType.rrw_else ) 5733 { 5734 // { .. } else 5735 gst = EFindSqlStateType.stsql; 5736 } 5737 else if ( lcnextsolidtoken.tokentype == ETokenType.ttsemicolon ) 5738 { 5739 lcnnextsolidtoken = sourcetokenlist.nextsolidtoken(lcnextsolidtoken.posinlist,1,false); 5740 if ( TBaseType.assigned(lcnnextsolidtoken) ) 5741 { 5742 if ( lcnnextsolidtoken.tokencode == TBaseType.rrw_else ) 5743 { 5744 // { .. } else 5745 gst = EFindSqlStateType.stsql; 5746 } 5747 } 5748 } 5749 } 5750 } 5751 5752 if ( gst != EFindSqlStateType.stsql ) 5753 { 5754 doongetrawsqlstatementevent(gcurrentsqlstatement); 5755 gst = EFindSqlStateType.stnormal; 5756 } 5757 5758 } 5759 else 5760 { 5761 lcblocklevel--; 5762 } 5763 5764 } 5765 } 5766 } 5767 break; 5768 } 5769 case sttrycatch: 5770 { 5771 5772 if ( TBaseType.assigned(lcnextsqlstatement) ) 5773 { 5774 if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo ) 5775 { 5776 doongetrawsqlstatementevent(gcurrentsqlstatement); 5777 gcurrentsqlstatement = lcnextsqlstatement; 5778 gcurrentsqlstatement.addtokentolist(ast); 5779 doongetrawsqlstatementevent(gcurrentsqlstatement); 5780 gst = EFindSqlStateType.stnormal; 5781 } 5782 else 5783 { 5784 if ( 5785 (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry) 5786 ||(lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 5787 ) 5788 lctrycatchlevel++; 5789 lcnextsqlstatement = null; 5790 } 5791 } 5792 5793 if ( gst == EFindSqlStateType.sttrycatch ) 5794 { 5795 gcurrentsqlstatement.addtokentolist(ast); 5796 if ( (ast.tokencode == TBaseType.rrw_try) || 5797 (ast.tokencode == TBaseType.rrw_catch) ) 5798 { 5799 // lcprevsolidtoken = sourcetokenlist.solidtokenbefore(i); 5800 if ( TBaseType.assigned(lcprevsolidtoken) ) 5801 { 5802 if ( lcprevsolidtoken.tokencode == TBaseType.rrw_end ) 5803 { 5804 if ( lctrycatchlevel == 0 ) 5805 { 5806 doongetrawsqlstatementevent(gcurrentsqlstatement); 5807 gst = EFindSqlStateType.stnormal; 5808 } 5809 else 5810 lctrycatchlevel--; 5811 } 5812 } 5813 } 5814 } 5815 break; 5816 } 5817 case stprocedureWithReturn: 5818 { 5819 // found return statement in create procedure/function, which means can be ended with a semicolon 5820 5821 if ( TBaseType.assigned(lcnextsqlstatement) ) { 5822 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo) { 5823 doongetrawsqlstatementevent(gcurrentsqlstatement); 5824 gcurrentsqlstatement = lcnextsqlstatement; 5825 gcurrentsqlstatement.addtokentolist(ast); 5826 doongetrawsqlstatementevent(gcurrentsqlstatement); 5827 gst = EFindSqlStateType.stnormal; 5828 break; 5829 } 5830 } 5831 5832 gcurrentsqlstatement.addtokentolist(ast); 5833 if ((gst == EFindSqlStateType.stprocedureWithReturn) && (ast.tokentype == ETokenType.ttsemicolon)){ 5834 5835 doongetrawsqlstatementevent(gcurrentsqlstatement); 5836 gst = EFindSqlStateType.stnormal; 5837 } 5838 break; 5839 } 5840 case stsql : 5841 { 5842 if ( (ast.tokentype == ETokenType.ttsemicolon) ) 5843 { 5844 lcstillinsql = false; 5845 if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif ) 5846 { 5847 lcnextsolidtoken = sourcetokenlist.nextsolidtoken(i,1,false); 5848 if ( TBaseType.assigned(lcnextsolidtoken) ) 5849 { 5850 if ( lcnextsolidtoken.tokencode == TBaseType.rrw_else ) 5851 { 5852 // if ( expr stmt; else 5853 gcurrentsqlstatement.addtokentolist(ast); 5854 lcstillinsql = true; 5855 } 5856 5857 } 5858 } 5859 5860 if ( !lcstillinsql ) 5861 { 5862 gst = EFindSqlStateType.stnormal; 5863 gcurrentsqlstatement.addtokentolist(ast); 5864 gcurrentsqlstatement.semicolonended = ast; 5865 doongetrawsqlstatementevent(gcurrentsqlstatement); 5866 } 5867 5868 } 5869 else if ( TBaseType.assigned(lcnextsqlstatement) ) 5870 { 5871 5872 if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo ) 5873 { 5874 doongetrawsqlstatementevent(gcurrentsqlstatement); 5875 gcurrentsqlstatement = lcnextsqlstatement; 5876 gcurrentsqlstatement.addtokentolist(ast); 5877 doongetrawsqlstatementevent(gcurrentsqlstatement); 5878 gst = EFindSqlStateType.stnormal; 5879 continue; 5880 } 5881 5882 switch(gcurrentsqlstatement.sqlstatementtype){ // 5883 case sstmssqlif: 5884 case sstmssqlwhile: 5885 { 5886 if ((lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegincatch) 5887 ||(lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlbegintry)) 5888 { 5889 gcurrentsqlstatement.addtokentolist(ast); 5890 gst = EFindSqlStateType.stblock; 5891 lcblocklevel = 1; 5892 lcnextsqlstatement = null; 5893 continue; 5894 5895 } 5896 // if ( || while only contain one sql(not closed by {/} pair) 5897 // so will still in if ( || while statement 5898 else if ( gcurrentsqlstatement.dummytag == 1 ) 5899 { 5900 // if ( cond ^stmt nextstmt (^ stands for current pos) 5901 gcurrentsqlstatement.addtokentolist(ast); 5902 5903 if ( (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 5904 || (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 5905 ) 5906 gcurrentsqlstatement.dummytag = 1; 5907 else 5908 gcurrentsqlstatement.dummytag = 0; 5909 5910 5911 lcnextsqlstatement = null; 5912 continue; 5913 }else{ 5914 // 在 if statement 中,已经遇见过第一个sql语句,现在是碰到第二个,正常情况下这个第二个 5915 //IF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[DF_TEST]') AND type = 'D') 5916 //ALTER TABLE test DROP CONSTRAINT IF EXISTS DF_TEST; 5917 5918 if (lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif){ 5919 // 上例中的第二个 IF EXISTS 不是真正的 sql, 忽略它 5920 if ((ast.nextSolidToken() != null)&&(ast.nextSolidToken().tokencode == TBaseType.rrw_sqlserver_exists)){ 5921 gcurrentsqlstatement.addtokentolist(ast); 5922 lcnextsqlstatement = null; 5923 continue; 5924 } 5925 } 5926 } 5927 break; 5928 }// 5929 case sstmssqlalterqueue: 5930 { 5931 if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlexec ) 5932 { 5933 // execute can't be used to delimite alter queue 5934 gcurrentsqlstatement.addtokentolist(ast); 5935 lcnextsqlstatement = null; 5936 continue; 5937 5938 } 5939 break; 5940 } 5941 case sstmssqlcreateschema: 5942 { 5943 gcurrentsqlstatement.addtokentolist(ast); 5944 lcnextsqlstatement = null; 5945 continue; 5946 } 5947 }//case 5948 5949 doongetrawsqlstatementevent(gcurrentsqlstatement); 5950 gcurrentsqlstatement = lcnextsqlstatement; 5951 gcurrentsqlstatement.addtokentolist(ast); 5952 5953 switch(gcurrentsqlstatement.sqlstatementtype){ // 5954 case sstmssqlcreateprocedure: 5955 case sstmssqlcreatefunction: 5956 //case sstmssqlcreatetrigger: 5957 case sstcreatetrigger: 5958 case sstmssqlalterprocedure: 5959 case sstmssqlalterfunction: 5960 case sstmssqlaltertrigger: 5961 { 5962 gst = EFindSqlStateType.ststoredprocedure; 5963 break; 5964 } 5965 case sstmssqlbegintry: 5966 case sstmssqlbegincatch: 5967 { 5968 gst = EFindSqlStateType.sttrycatch; 5969 lctrycatchlevel = 0; 5970 break; 5971 } 5972 case sstmssqlgo: 5973 { 5974 gst = EFindSqlStateType.stnormal; 5975 break; 5976 } 5977 default: 5978 { 5979 gst = EFindSqlStateType.stsql; 5980 break; 5981 } 5982 } // case 5983 5984 }//TBaseType.assigned(lcnextsqlstatement) 5985 else if ( (ast.tokencode == TBaseType.rrw_begin) ) 5986 { 5987 if ( (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 5988 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 5989 ) 5990 { 5991 // start block of if ( || while statement 5992 gst = EFindSqlStateType.stblock; 5993 lcblocklevel = 0; 5994 gcurrentsqlstatement.addtokentolist(ast); 5995 } 5996 else if ( gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqldeclare ) 5997 { 5998 doongetrawsqlstatementevent(gcurrentsqlstatement); 5999 gcurrentsqlstatement = new TMssqlBlock(dbVendor); 6000 gcurrentsqlstatement.sqlstatementtype = ESqlStatementType.sstmssqlblock; 6001 gcurrentsqlstatement.addtokentolist(ast); 6002 gst = EFindSqlStateType.stblock; 6003 } 6004 else 6005 { 6006 gcurrentsqlstatement.addtokentolist(ast); 6007 } 6008 } 6009 else if ( (ast.tokencode == TBaseType.rrw_case) ){ 6010 case_end_nest++; 6011 gcurrentsqlstatement.addtokentolist(ast); 6012 } 6013 else if ( (ast.tokencode == TBaseType.rrw_end) ){ 6014 if (case_end_nest > 0){ 6015 case_end_nest--; 6016 } 6017 gcurrentsqlstatement.addtokentolist(ast); 6018 } 6019 else if ( (ast.tokencode == TBaseType.rrw_else) ) 6020 { 6021 gcurrentsqlstatement.addtokentolist(ast); 6022 // if ( cond stmt ^else stmt 6023 if (( (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlif) 6024 || (gcurrentsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlwhile) 6025 ) && (case_end_nest == 0)) 6026 gcurrentsqlstatement.dummytag = 1; // reduce to 1 while stmt after else is found: if ( cond stmt ^else stmt 6027 } 6028 else 6029 { 6030 gcurrentsqlstatement.addtokentolist(ast); 6031 } 6032 break; 6033 } 6034 case ststoredprocedure: 6035 { 6036 if ( TBaseType.assigned(lcnextsqlstatement) ) 6037 { 6038 if ( lcnextsqlstatement.sqlstatementtype == ESqlStatementType.sstmssqlgo ) 6039 { 6040 doongetrawsqlstatementevent(gcurrentsqlstatement); 6041 gcurrentsqlstatement = lcnextsqlstatement; 6042 gcurrentsqlstatement.addtokentolist(ast); 6043 doongetrawsqlstatementevent(gcurrentsqlstatement); 6044 gst = EFindSqlStateType.stnormal; 6045 } 6046 else if (lcnextsqlstatement.sqlstatementtype == sstmssqlreturn) 6047 { 6048 gst = EFindSqlStateType.stprocedureWithReturn; 6049 gcurrentsqlstatement.addtokentolist(ast); 6050 lcnextsqlstatement = null; 6051 } 6052 else 6053 { 6054 gst = EFindSqlStateType.ststoredprocedurebody; 6055 gcurrentsqlstatement.addtokentolist(ast); 6056 6057 lcnextsqlstatement = null; 6058 } 6059 } 6060 6061 if ( gst == EFindSqlStateType.ststoredprocedure ) 6062 { 6063 gcurrentsqlstatement.addtokentolist(ast); 6064 if ( ast.tokencode == TBaseType.rrw_begin ) 6065 { 6066 gst = EFindSqlStateType.stblock; 6067 } 6068 } 6069 break; 6070 } //stplsql 6071 case ststoredprocedurebody: 6072 { 6073 if ( TBaseType.assigned(lcnextsqlstatement) ) 6074 { 6075 switch(lcnextsqlstatement.sqlstatementtype){ // 6076 case sstmssqlgo: 6077 { 6078 doongetrawsqlstatementevent(gcurrentsqlstatement); 6079 gcurrentsqlstatement = lcnextsqlstatement; 6080 gcurrentsqlstatement.addtokentolist(ast); 6081 doongetrawsqlstatementevent(gcurrentsqlstatement); 6082 gst = EFindSqlStateType.stnormal; 6083 break; 6084 } 6085 case sstmssqlcreateprocedure: 6086 case sstmssqlcreatefunction: 6087 //case sstmssqlcreatetrigger: 6088 case sstcreatetrigger: 6089 case sstmssqlalterprocedure: 6090 case sstmssqlalterfunction: 6091 case sstmssqlaltertrigger: 6092 { 6093 doongetrawsqlstatementevent(gcurrentsqlstatement); 6094 gcurrentsqlstatement = lcnextsqlstatement; 6095 gcurrentsqlstatement.addtokentolist(ast); 6096 gst = EFindSqlStateType.ststoredprocedure; 6097 break; 6098 } 6099 case sstcreateview: 6100 case sstcreatetable: 6101 { 6102 6103 boolean readForNewStmt = false; 6104 TSourceToken st1 = ast.searchToken(';',-1); 6105 if (st1 != null) { 6106 TSourceToken st2 = ast.searchToken(TBaseType.rrw_end,-2); 6107 if (st2 != null){ 6108 readForNewStmt = true; 6109 } 6110 } 6111 6112 if (readForNewStmt){ 6113 doongetrawsqlstatementevent(gcurrentsqlstatement); 6114 gcurrentsqlstatement = lcnextsqlstatement; 6115 gcurrentsqlstatement.addtokentolist(ast); 6116 gst = EFindSqlStateType.stsql; 6117 }else{ 6118 lcnextsqlstatement = null; 6119 } 6120 break; 6121 } 6122 case sstmssqlDropSecurityPolicy: 6123 case sstmssqlAlterSecurityPolicy: 6124 case sstmssqlCreateSecurityPolicy: 6125 doongetrawsqlstatementevent(gcurrentsqlstatement); 6126 gcurrentsqlstatement = lcnextsqlstatement; 6127 gcurrentsqlstatement.addtokentolist(ast); 6128 gst = EFindSqlStateType.stsql; 6129 6130 break; 6131 default: 6132 { 6133 lcnextsqlstatement = null; 6134 break; 6135 } 6136 }//case 6137 } 6138 6139 if ( gst == EFindSqlStateType.ststoredprocedurebody ) 6140 gcurrentsqlstatement.addtokentolist(ast); 6141 } 6142 break; 6143 } //case 6144 } //for 6145 6146 6147 //last statement 6148 if ( TBaseType.assigned(gcurrentsqlstatement) && (gst != EFindSqlStateType.stnormal)) 6149 { 6150 doongetrawsqlstatementevent(gcurrentsqlstatement,true); 6151 } 6152 6153 return errorcount; 6154 6155 } 6156 6157 6158 private TCustomSqlStatement startDaxStmt(TSourceToken currToken,TCustomSqlStatement currStmt){ 6159 TCustomSqlStatement newStmt = null; 6160 if (currToken == null) return null; 6161 if ((currToken.tokencode == '=')&&(currToken.isFirstTokenOfLine())){ 6162 currToken.tokencode = TBaseType.equal_start_expr; 6163 newStmt = new TDaxExprStmt(EDbVendor.dbvdax); 6164 }else if ((currToken.tokencode == TBaseType.rrw_dax_define)&&(currToken.isFirstTokenOfLine())){ 6165 newStmt = new TDaxEvaluateStmt(EDbVendor.dbvdax); 6166 ((TDaxEvaluateStmt)newStmt).setStartWithDefine(true); 6167 }else if ((currToken.tokencode == TBaseType.rrw_dax_evaluate)&&(currToken.isFirstTokenOfLine())){ 6168 if ((currStmt != null)&&(currStmt instanceof TDaxEvaluateStmt)){ 6169 TDaxEvaluateStmt tmp = (TDaxEvaluateStmt)currStmt; 6170 if (tmp.isStartWithDefine()) return null; 6171 } 6172 newStmt = new TDaxEvaluateStmt(EDbVendor.dbvdax); 6173 } 6174 6175 if (newStmt == null){ 6176 // let's check is this the first token of query 6177 boolean isFirst = currToken.isFirstTokenOfLine(); 6178 TSourceToken prevToken = currToken.prevSolidToken(); 6179 if ((isFirst)&&(prevToken == null)){ 6180 newStmt = new TDaxExprStmt(EDbVendor.dbvdax); 6181 } 6182 } 6183 return newStmt; 6184 } 6185 6186int dogetrawsqlstatements(){ 6187 6188 sqlstatements.clear(); 6189 if (sourcetokenlist.size() == 0) return -1; 6190 6191 switch(dbVendor){ 6192 case dbvpostgresql:{ 6193 return dopostgresqlgetrawsqlstatements(); 6194 } 6195 case dbvclickhouse:{ 6196 return doclickhousegetrawsqlstatements(); 6197 } 6198 default:{ 6199 return domssqlgetrawsqlstatements(); 6200 } 6201 } 6202 6203} 6204 6205 /** 6206 * separates the SQL statements in the input SQL script without doing syntax check. 6207 * <p></p> 6208 * Use the {@link #getSqlstatements()} method to get the list of SQL statements. 6209 * The SQL statement object is the instance of the sub-class of {@link TCustomSqlStatement}, get SQL statement type 6210 * via the {@link TCustomSqlStatement#sqlstatementtype} field, get string representation of 6211 * each SQL statement via the {@link TCustomSqlStatement#toString} method. 6212 * <p></p> 6213 * All source tokens in this SQL statement 6214 * is available by using {@link TCustomSqlStatement#sourcetokenlist} filed. 6215 * Since no parse tree is built by calling this method, no further detailed information about the SQL statement is available. 6216 * 6217 * @return 0 if get SQL statements successfully 6218 */ 6219public int getrawsqlstatements(){ 6220 // Check for vendor parser delegation (MSSQL, etc.) 6221 // This ensures raw-split logic is maintained in only one place (vendor parser) 6222 SqlParser vp = getOrCreateVendorParser(); 6223 if (vp != null) { 6224 return doDelegatedRawParse(vp); 6225 } 6226 6227 // Legacy path for non-delegated vendors 6228 int ret = readsql(); 6229 if (ret != 0) return ret; 6230 dosqltexttotokenlist(); 6231 6232 return dogetrawsqlstatements(); 6233} 6234 6235 /** 6236 * turns the input SQL into a sequence of token which is the 6237 * basic lexis element of SQL syntax. Token is categorized as keyword, identifier, 6238 * number, operator, whitespace and other types. All source tokens can be fetched 6239 * via the {@link #getSourcetokenlist()} method. 6240 * 6241 */ 6242public void tokenizeSqltext(){ 6243 // Check for vendor parser delegation (MSSQL, etc.) 6244 // This ensures tokenization logic is maintained in only one place (vendor parser) 6245 SqlParser vp = getOrCreateVendorParser(); 6246 if (vp != null) { 6247 doDelegatedTokenize(vp); 6248 return; 6249 } 6250 6251 // Legacy path for non-delegated vendors 6252 getFlexer(); 6253 readsql(); 6254 dosqltexttotokenlist(); 6255} 6256 6257/** 6258 * Delegate tokenization to vendor parser and backfill results. 6259 * Similar to doDelegatedRawParse but only performs tokenization. 6260 */ 6261private void doDelegatedTokenize(SqlParser vendorParser) { 6262 // Build context for vendor parser 6263 ParserContext context = buildContext(); 6264 6265 // Delegate tokenization to vendor parser 6266 SqlParseResult tokenResult = vendorParser.tokenize(context); 6267 6268 // Copy results back to TGSqlParser fields for backward compatibility 6269 if (tokenResult.getSourceTokenList() != null) { 6270 this.sourcetokenlist = tokenResult.getSourceTokenList(); 6271 } 6272 if (tokenResult.getLexer() != null) { 6273 this.flexer = tokenResult.getLexer(); 6274 } 6275} 6276 6277 6278 6279void findAllSyntaxErrorsInPlsql(TCustomSqlStatement psql){ 6280 if (psql.getErrorCount() > 0){ 6281 copyerrormsg(psql); 6282 } 6283 6284 for (int k=0;k<psql.getStatements().size();k++){ 6285 findAllSyntaxErrorsInPlsql(psql.getStatements().get(k)); 6286 } 6287 6288} 6289 6290private TSQLEnv sqlEnv = null; 6291 6292 /** 6293 * SQL environment includes the database metadata such as procedure, function, trigger, table and etc. 6294 * 6295 * In order to link column to table correctly without connecting to database, 6296 * we need to provide a class which implements {@link TSQLEnv} to TGSqlParser. 6297 * this class tells TGSqlParser the relationship between column and table. 6298 * 6299 * <p>Take this SQL for example: 6300 * <pre> 6301 * SELECT Quantity,b.Time,c.Description 6302 * FROM 6303 * (SELECT ID2,Time FROM bTab) b 6304 * INNER JOIN aTab a on a.ID=b.ID 6305 * INNER JOIN cTab c on a.ID=c.ID 6306 * </pre> 6307 * 6308 * <p>General SQL Parser can build relationship between column: ID2 and table: bTable 6309 * correctly without metadata information from database because there is only one table 6310 * in from clause. But it can't judge column: Quantity belong to table: aTab or cTab, 6311 * since no table alias was prefixed to column: Quantity. If no metadata provided, 6312 * General SQL Parser will link column: Quantity to the first valid table (here it is aTab) 6313 * 6314 * <p>If we create a class TRealDatabaseSQLEnv implements {@link TSQLEnv},then 6315 * {@link #setSqlEnv(TSQLEnv)}, General SQL Parser can take this advantage to create 6316 * a correct relationship between column and tables. 6317 * 6318 *<pre> 6319 * class TSQLServerEnv extends TSQLEnv{ 6320 * 6321 * public TSQLServerEnv(){ 6322 * super(EDbVendor.dbvmssql); 6323 * initSQLEnv(); 6324 * } 6325 * 6326 * @Override 6327 * public void initSQLEnv() { 6328 * 6329 * // add a new database: master 6330 * TSQLCatalog sqlCatalog = createSQLCatalog("master"); 6331 * // add a new schema: dbo 6332 * TSQLSchema sqlSchema = sqlCatalog.createSchema("dbo"); 6333 * //add a new table: aTab 6334 * TSQLTable aTab = sqlSchema.createTable("aTab"); 6335 * aTab.addColumn("Quantity1"); 6336 * 6337 * //add a new table: bTab 6338 * TSQLTable bTab = sqlSchema.createTable("bTab"); 6339 * bTab.addColumn("Quantity2"); 6340 * 6341 * //add a new table: cTab 6342 * TSQLTable cTab = sqlSchema.createTable("cTab"); 6343 * cTab.addColumn("Quantity"); 6344 * 6345 * } 6346 * } 6347 * </pre> 6348 * 6349 * @return SQL environment 6350 */ 6351 public TSQLEnv getSqlEnv() { 6352 return sqlEnv; 6353 } 6354 6355 private boolean onlyNeedRawParseTree = false; 6356 6357 public void setOnlyNeedRawParseTree(boolean onlyNeedRawParseTree) { 6358 this.onlyNeedRawParseTree = onlyNeedRawParseTree; 6359 } 6360 6361 public void setSqlEnv(TSQLEnv sqlEnv) { 6362 this.sqlEnv = sqlEnv; 6363 } 6364 6365 6366 // Time tracking variables 6367 private boolean enableTimeLogging = false; 6368 private long rawSqlStatementsTime = 0; 6369 private long parsingTime = 0; 6370 private long semanticAnalysisTime = 0; 6371 private long interpreterTime = 0; 6372 6373 /** 6374 * Enable or disable time logging for parser steps 6375 * @param enable true to enable time logging, false to disable 6376 */ 6377 public void setEnableTimeLogging(boolean enable) { 6378 this.enableTimeLogging = enable; 6379 } 6380 6381 /** 6382 * Check if time logging is enabled 6383 * @return true if time logging is enabled, false otherwise 6384 */ 6385 public boolean isTimeLoggingEnabled() { 6386 return this.enableTimeLogging; 6387 } 6388 6389 /** 6390 * Reset all accumulated time counters to zero 6391 */ 6392 public void resetTimeCounters() { 6393 rawSqlStatementsTime = 0; 6394 parsingTime = 0; 6395 semanticAnalysisTime = 0; 6396 interpreterTime = 0; 6397 } 6398 6399 /** 6400 * Get accumulated time spent getting raw SQL statements in milliseconds 6401 * @return time in milliseconds 6402 */ 6403 public long getRawSqlStatementsTime() { 6404 return rawSqlStatementsTime; 6405 } 6406 6407 /** 6408 * Get accumulated time spent parsing in milliseconds 6409 * @return time in milliseconds 6410 */ 6411 public long getParsingTime() { 6412 return parsingTime; 6413 } 6414 6415 /** 6416 * Get accumulated time spent on semantic analysis in milliseconds 6417 * @return time in milliseconds 6418 */ 6419 public long getSemanticAnalysisTime() { 6420 return semanticAnalysisTime; 6421 } 6422 6423 /** 6424 * Get accumulated time spent in interpreter in milliseconds 6425 * @return time in milliseconds 6426 */ 6427 public long getInterpreterTime() { 6428 return interpreterTime; 6429 } 6430 6431 /** 6432 * Get total accumulated time spent in all steps 6433 * @return total time in milliseconds 6434 */ 6435 public long getTotalTime() { 6436 return rawSqlStatementsTime + parsingTime + semanticAnalysisTime + interpreterTime; 6437 } 6438 6439 /** 6440 * Get or create the vendor-specific parser for delegation. 6441 * The parser is cached in vendorParser field and reused for subsequent calls. 6442 * This allows getFlexer() to lazily create the parser to access its lexer. 6443 * 6444 * @return vendor-specific SqlParser or null if not a delegated vendor 6445 * @since 3.2.0.0 6446 */ 6447 private SqlParser getOrCreateVendorParser() { 6448 // Return cached parser if available 6449 if (vendorParser != null) { 6450 return vendorParser; 6451 } 6452 6453 // Create new vendor parser based on database vendor 6454 switch (dbVendor) { 6455 case dbvmssql: 6456 case dbvazuresql: 6457 vendorParser = new gudusoft.gsqlparser.parser.MssqlSqlParser(); 6458 break; 6459 case dbvmysql: 6460 vendorParser = new gudusoft.gsqlparser.parser.MySqlSqlParser(); 6461 break; 6462 case dbvpostgresql: 6463 vendorParser = new gudusoft.gsqlparser.parser.PostgreSqlParser(); 6464 break; 6465 case dbvoracle: 6466 vendorParser = new gudusoft.gsqlparser.parser.OracleSqlParser(); 6467 break; 6468 case dbvbigquery: 6469 vendorParser = new gudusoft.gsqlparser.parser.BigQuerySqlParser(); 6470 break; 6471 case dbvathena: 6472 vendorParser = new gudusoft.gsqlparser.parser.AthenaSqlParser(); 6473 break; 6474 case dbvcouchbase: 6475 vendorParser = new gudusoft.gsqlparser.parser.CouchbaseSqlParser(); 6476 break; 6477 case dbvdatabricks: 6478 vendorParser = new gudusoft.gsqlparser.parser.DatabricksSqlParser(); 6479 break; 6480 case dbvdax: 6481 vendorParser = new gudusoft.gsqlparser.parser.DaxSqlParser(); 6482 break; 6483 case dbvdb2: 6484 vendorParser = new gudusoft.gsqlparser.parser.Db2SqlParser(); 6485 break; 6486 case dbvgaussdb: 6487 vendorParser = new gudusoft.gsqlparser.parser.GaussDbSqlParser(); 6488 break; 6489 case dbvgreenplum: 6490 vendorParser = new gudusoft.gsqlparser.parser.GreenplumSqlParser(); 6491 break; 6492 case dbvhive: 6493 vendorParser = new gudusoft.gsqlparser.parser.HiveSqlParser(); 6494 break; 6495 case dbvhana: 6496 vendorParser = new gudusoft.gsqlparser.parser.HanaSqlParser(); 6497 break; 6498 case dbvimpala: 6499 vendorParser = new gudusoft.gsqlparser.parser.ImpalaSqlParser(); 6500 break; 6501 case dbvinformix: 6502 vendorParser = new gudusoft.gsqlparser.parser.InformixSqlParser(); 6503 break; 6504 case dbvmdx: 6505 vendorParser = new gudusoft.gsqlparser.parser.MdxSqlParser(); 6506 break; 6507 case dbvnetezza: 6508 vendorParser = new gudusoft.gsqlparser.parser.NetezzaSqlParser(); 6509 break; 6510 case dbvodbc: 6511 vendorParser = new gudusoft.gsqlparser.parser.OdbcSqlParser(); 6512 break; 6513 case dbvopenedge: 6514 vendorParser = new gudusoft.gsqlparser.parser.OpenEdgeSqlParser(); 6515 break; 6516 case dbvpresto: 6517 vendorParser = new gudusoft.gsqlparser.parser.PrestoSqlParser(); 6518 break; 6519 case dbvredshift: 6520 vendorParser = new gudusoft.gsqlparser.parser.RedshiftSqlParser(); 6521 break; 6522 case dbvsnowflake: 6523 vendorParser = new gudusoft.gsqlparser.parser.SnowflakeSqlParser(); 6524 break; 6525 case dbvsoql: 6526 vendorParser = new gudusoft.gsqlparser.parser.SoqlSqlParser(); 6527 break; 6528 case dbvsparksql: 6529 vendorParser = new gudusoft.gsqlparser.parser.SparksqlSqlParser(); 6530 break; 6531 case dbvsybase: 6532 vendorParser = new gudusoft.gsqlparser.parser.SybaseSqlParser(); 6533 break; 6534 case dbvteradata: 6535 vendorParser = new gudusoft.gsqlparser.parser.TeradataSqlParser(); 6536 break; 6537 case dbvvertica: 6538 vendorParser = new gudusoft.gsqlparser.parser.VerticaSqlParser(); 6539 break; 6540 case dbvansi: 6541 vendorParser = new gudusoft.gsqlparser.parser.AnsiSqlParser(); 6542 break; 6543 default: 6544 return null; 6545 } 6546 return vendorParser; 6547 } 6548 6549 /** 6550 * Prepare this parser for reuse by clearing cached state. 6551 * This is useful when reusing a TGSqlParser instance (e.g., in TExecImmeStmt) 6552 * to avoid state pollution between parsing operations. 6553 * 6554 * Clears: vendorParser, sqlEnv, sqlfilename, and resets parsing options. 6555 * 6556 * @since 3.2.0.0 6557 */ 6558 public void prepareForReuse() { 6559 // Clear cached vendor parser to force recreation 6560 this.vendorParser = null; 6561 // Clear SQL environment to avoid old schema information affecting new parse 6562 this.sqlEnv = null; 6563 // Clear filename in case it was set previously 6564 this.sqlfilename = null; 6565 // Reset parsing options to defaults 6566 this.isSinglePLBlock = false; 6567 // Clear statement list 6568 if (this.sqlstatements != null) { 6569 this.sqlstatements.clear(); 6570 } 6571 // Clear error state 6572 this.syntaxErrors.clear(); 6573 } 6574 6575 /** 6576 * Build a ParserContext from current TGSqlParser state. 6577 * This creates an immutable context for delegation to vendor parsers. 6578 * 6579 * @return immutable ParserContext 6580 * @since 3.2.0.0 6581 */ 6582 private ParserContext buildContext() { 6583 ParserContext.Builder builder = new ParserContext.Builder(this.dbVendor); 6584 6585 // Set SQL text source (only one will be non-null or non-empty) 6586 // CRITICAL: Check for non-null AND non-empty because TGSqlParser initializes sqltext="" 6587 // which would cause vendor parser to use empty string instead of reading from file 6588 if (this.sqltext != null && !this.sqltext.isEmpty()) { 6589 builder.sqlText(this.sqltext); 6590 } 6591 if (this.sqlfilename != null && !this.sqlfilename.isEmpty()) { 6592 builder.sqlFilename(this.sqlfilename); 6593 } 6594 6595 // Set charset 6596 if (this.sqlCharset != null) { 6597 builder.sqlCharset(this.sqlCharset); 6598 } 6599 6600 // Set parsing options 6601 builder.enablePartialParsing(this.isEnablePartialParsing()); 6602 builder.singlePLBlock(this.isSinglePLBlock); 6603 6604 // Set gsqlparser reference for backward compatibility 6605 builder.gsqlparser(this); 6606 6607 // Set SQL environment if available 6608 if (this.sqlEnv != null) { 6609 builder.sqlEnv(this.sqlEnv); 6610 } 6611 6612 // Set token handle for callback during tokenization 6613 if (this.tokenHandle != null) { 6614 builder.tokenHandle(this.tokenHandle); 6615 } 6616 6617 return builder.build(); 6618 } 6619 6620 /** 6621 * Returns time statistics as a formatted string 6622 * @return formatted string with time statistics 6623 */ 6624 public String getTimeStatistics() { 6625 if (!enableTimeLogging) { 6626 return "Time logging is disabled"; 6627 } 6628 6629 StringBuilder sb = new StringBuilder(); 6630 sb.append(String.format("Time statistics for TGSqlParser version: %s, released at: %s, dbvendor: %s:\n", TBaseType.versionid,TBaseType.releaseDate, this.dbVendor)); 6631 sb.append(String.format("1. Raw SQL statements: %d ms (%.2f%%)\n", 6632 rawSqlStatementsTime, 6633 getTotalTime() > 0 ? 100.0 * rawSqlStatementsTime / getTotalTime() : 0)); 6634 sb.append(String.format("2. Parsing: %d ms (%.2f%%)\n", 6635 parsingTime, 6636 getTotalTime() > 0 ? 100.0 * parsingTime / getTotalTime() : 0)); 6637 sb.append(String.format("3. Semantic analysis: %d ms (%.2f%%)\n", 6638 semanticAnalysisTime, 6639 getTotalTime() > 0 ? 100.0 * semanticAnalysisTime / getTotalTime() : 0)); 6640 sb.append(String.format("4. Interpreter: %d ms (%.2f%%)\n", 6641 interpreterTime, 6642 getTotalTime() > 0 ? 100.0 * interpreterTime / getTotalTime() : 0)); 6643 sb.append(String.format("Total: %d ms", getTotalTime())); 6644 return sb.toString(); 6645 } 6646 6647 /** 6648 * Delegate only tokenization and raw statement extraction to vendor parser. 6649 * The actual AST parsing is done by the common parsing loop in doparse(). 6650 * This architecture ensures that: 6651 * 1. Vendor-specific tokenization/lexing is handled by vendor parser 6652 * 2. Raw statement extraction (splitting SQL text into statements) is vendor-specific 6653 * 3. AST parsing (building parse tree for each statement) uses common code path 6654 * 6655 * @param vendorParser the vendor-specific parser to use 6656 * @return 0 if successful, non-zero on error 6657 */ 6658 private int doDelegatedRawParse(SqlParser vendorParser) { 6659 long phaseStart, phaseEnd; 6660 6661 // Build context for vendor parser 6662 ParserContext context = buildContext(); 6663 6664 // Delegate only tokenization + raw statement extraction to vendor parser 6665 phaseStart = enableTimeLogging ? System.currentTimeMillis() : 0; 6666 SqlParseResult rawResult = vendorParser.getrawsqlstatements(context); 6667 if (enableTimeLogging) { 6668 phaseEnd = System.currentTimeMillis(); 6669 rawSqlStatementsTime += (phaseEnd - phaseStart); 6670 } 6671 6672 // Copy results back to TGSqlParser fields for backward compatibility 6673 if (rawResult.getSourceTokenList() != null) { 6674 this.sourcetokenlist = rawResult.getSourceTokenList(); 6675 this.sourcetokenlist.setGsqlparser(this); 6676 } 6677 if (rawResult.getLexer() != null) { 6678 this.flexer = rawResult.getLexer(); 6679 } 6680 // Copy parser from vendor parser result - needed for parsestatement() 6681 if (rawResult.getParser() != null) { 6682 this.fparser = rawResult.getParser(); 6683 // CRITICAL: Set gsqlparser on NodeFactory for correct AST construction 6684 this.fparser.getNf().setGsqlParser(this); 6685 } 6686 // Copy secondary parser (for Oracle PL/SQL) and set its NodeFactory 6687 if (rawResult.getSecondaryParser() != null) { 6688 this.fplsqlparser = rawResult.getSecondaryParser(); 6689 // CRITICAL: Also set gsqlparser on secondary parser's NodeFactory 6690 // This is needed for Oracle PL/SQL statements which use fplsqlparser for parsing 6691 this.fplsqlparser.getNf().setGsqlParser(this); 6692 } 6693 if (rawResult.getSqlStatements() != null) { 6694 this.sqlstatements = rawResult.getSqlStatements(); 6695 } 6696 6697 // Copy any tokenization errors 6698 if (rawResult.getSyntaxErrors() != null) { 6699 for (TSyntaxError error : rawResult.getSyntaxErrors()) { 6700 this.syntaxErrors.add(error); 6701 } 6702 } 6703 6704 return rawResult.getErrorCode(); 6705 } 6706 6707 int doparse() { 6708 int j; 6709 long startTime, endTime; 6710 boolean useDelegatedRawParse = false; 6711 6712 // 1. Get raw SQL statements 6713 // For delegated vendors, use vendor parser for tokenization + raw extraction 6714 // The parsing loop below is common for all vendors 6715 SqlParser vp = getOrCreateVendorParser(); 6716 if (vp != null) { 6717 int ret = doDelegatedRawParse(vp); 6718 if (ret != 0) { 6719 // Tokenization/extraction failed, return error 6720 return ret; 6721 } 6722 useDelegatedRawParse = true; 6723 // Continue to common parsing loop below 6724 } 6725 6726 // Legacy path: get raw statements for non-delegated vendors 6727 if (!useDelegatedRawParse) { 6728 startTime = enableTimeLogging ? System.currentTimeMillis() : 0; 6729 6730 int ret = getrawsqlstatements(); 6731 6732 if (enableTimeLogging) { 6733 endTime = System.currentTimeMillis(); 6734 rawSqlStatementsTime += (endTime - startTime); 6735 } 6736 } 6737 6738 boolean isPushGloablStack = false; 6739 //if (ret != 0) return ret; 6740 TFrame firstFrame = null; 6741 6742 globalContext = new TContext(); 6743 6744 if (this.sqlEnv == null) { 6745 this.sqlEnv = new TSQLEnv(this.dbVendor) { 6746 @Override 6747 public void initSQLEnv() { 6748 } 6749 }; 6750 // this.sqlEnv.setEnableGetMetadataFromDDL(false); 6751 } 6752 globalContext.setSqlEnv(this.sqlEnv, this.sqlstatements); 6753 6754 //TStackFrame stackFrame = new TStackFrame(new TGlobalScope()); 6755 if (getFrameStack().size() == 0) { // stack passed from outside gsqlparser will contain frames 6756 //getFrameStack().push(new TStackFrame(new TGlobalScope())); 6757 TGlobalScope globalScope = new TGlobalScope(); 6758 globalScope.resetCurrentStmtIndex(); 6759 6760 globalScope.setSqlEnv(this.sqlEnv); 6761 firstFrame = new TFrame(globalScope); 6762 firstFrame.pushMeToStack(getFrameStack()); 6763 isPushGloablStack = true; 6764 } 6765 6766 // 2. start parsing 6767 startTime = enableTimeLogging ? System.currentTimeMillis() : 0; 6768 6769 for (int i = 0; i < sqlstatements.size(); i++) { 6770 sqlstatements.getRawSql(i).setFrameStack(frameStack); 6771 j = sqlstatements.getRawSql(i).parsestatement(null, false, onlyNeedRawParseTree); 6772 6773 // NOTE: No need for setGsqlparserRecursively() here for delegated vendors. 6774 // The gsqlparser reference is already set on all AST nodes through two mechanisms: 6775 // 1. doDelegatedRawParse() sets fparser.getNf().setGsqlParser(this) and 6776 // fplsqlparser.getNf().setGsqlParser(this) BEFORE parsestatement() is called 6777 // 2. TNodeFactory.createNode() propagates gsqlparser to every node it creates 6778 // The recursive walk was causing 4-5x performance degradation for Oracle parsing 6779 // by redundantly traversing the entire AST after parsing. 6780 6781 TCustomSqlStatement sql0 = null; 6782 if (sqlstatements.get(i).isoracleplsql()) { 6783 // check syntax error in select/insert statement inside plsql 6784 sql0 = sqlstatements.get(i); 6785 findAllSyntaxErrorsInPlsql(sql0); 6786 } 6787 6788 boolean doRecover = TBaseType.ENABLE_ERROR_RECOVER_IN_CREATE_TABLE; 6789 6790 if (doRecover && ((j != 0) || (sqlstatements.get(i).getErrorCount() > 0))) { 6791 if (((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatetable) 6792 || ((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreateindex) && (dbVendor != EDbVendor.dbvcouchbase)) 6793 ) && (!TBaseType.c_createTableStrictParsing) 6794 ) { 6795 // only parse main body of create table, 6796 TCustomSqlStatement errorSqlStatement = (TCustomSqlStatement) sqlstatements.get(i); 6797 6798 int nested = 0; 6799 boolean isIgnore = false, isFoundIgnoreToken = false; 6800 TSourceToken firstIgnoreToken = null; 6801 for (int k = 0; k < errorSqlStatement.sourcetokenlist.size(); k++) { 6802 TSourceToken st = errorSqlStatement.sourcetokenlist.get(k); 6803 if (isIgnore) { 6804 if (st.issolidtoken() && (st.tokencode != ';')) { 6805 isFoundIgnoreToken = true; 6806 if (firstIgnoreToken == null) { 6807 firstIgnoreToken = st; 6808 } 6809 } 6810 if (st.tokencode != ';') { 6811 st.tokencode = TBaseType.sqlpluscmd; 6812 } 6813 continue; 6814 } 6815 if (st.tokencode == (int) ')') { 6816 nested--; 6817 if (nested == 0) { 6818 //let's check is next token is 6819 // as ( select 6820 boolean isSelect = false; 6821 TSourceToken st1 = st.searchToken(TBaseType.rrw_as, 1); 6822 if (st1 != null) { 6823 TSourceToken st2 = st.searchToken((int) '(', 2); 6824 if (st2 != null) { 6825 TSourceToken st3 = st.searchToken(TBaseType.rrw_select, 3); 6826 isSelect = (st3 != null); 6827 } 6828 } 6829 if (!isSelect) isIgnore = true; 6830 } 6831 } 6832 if ((st.tokencode == (int) '(') || (st.tokencode == TBaseType.left_parenthesis_2)) { 6833 nested++; 6834 } 6835 } 6836 6837 if ((dbVendor == EDbVendor.dbvoracle) && ((firstIgnoreToken != null) && (!TBaseType.searchOracleTablePros(firstIgnoreToken.toString())))) { 6838 // if it is not the valid Oracle table properties option, let raise the error. 6839 isFoundIgnoreToken = false; 6840 } 6841 if (isFoundIgnoreToken) { 6842 errorSqlStatement.clearError(); 6843 j = sqlstatements.get(i).parsestatement(null, false); 6844 } 6845 } 6846 6847 if (((sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatetrigger) 6848 || (sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstcreatefunction) 6849 || (sqlstatements.get(i).sqlstatementtype == sstcreateprocedure) 6850 ) && (dbVendor == EDbVendor.dbvdb2)) { 6851 // db2 can handle Oracle pl/sql code, so we give it a try here 6852 TCustomSqlStatement stmt = sqlstatements.get(i); 6853 StringBuffer stmtStr = new StringBuffer(1024); 6854 for (int k = 0; k < stmt.sourcetokenlist.size(); k++) { 6855 stmtStr.append(stmt.sourcetokenlist.get(k).getAstext()); 6856 } 6857 6858 TGSqlParser lc_sqlparser = new TGSqlParser(EDbVendor.dbvoracle); 6859 lc_sqlparser.sqltext = stmtStr.toString(); 6860 int iRet = lc_sqlparser.parse(); 6861 if (iRet == 0) { 6862 sqlstatements.remove(i); 6863 sqlstatements.add(i, lc_sqlparser.sqlstatements.get(0)); 6864 continue; 6865 } 6866 } 6867 } 6868 6869 if ((j != 0) || (sqlstatements.get(i).getErrorCount() > 0)) { 6870 copyerrormsg(sqlstatements.get(i)); 6871 6872 if ((isEnablePartialParsing()) && (dbVendor == EDbVendor.dbvsybase) && (sqlstatements.get(i).sqlstatementtype == ESqlStatementType.sstmssqlcreateprocedure)) { 6873 TMssqlCreateProcedure createProcedure = (TMssqlCreateProcedure) sqlstatements.get(i); 6874 6875 StringBuffer storedProcedure = new StringBuffer(1024); 6876 boolean ASKeyword = false; 6877 for (int k = 0; k < createProcedure.sourcetokenlist.size(); k++) { 6878 if ((!ASKeyword) && (createProcedure.sourcetokenlist.get(k).tokencode == TBaseType.rrw_as)) { 6879 ASKeyword = true; 6880 continue; 6881 } 6882 if (ASKeyword) { 6883 storedProcedure.append(createProcedure.sourcetokenlist.get(k).getAstext()); 6884 } 6885 } 6886 6887 TGSqlParser lc_sqlparser = new TGSqlParser(dbVendor); 6888 lc_sqlparser.sqltext = storedProcedure.toString(); 6889 lc_sqlparser.parse(); 6890 for (int k = 0; k < lc_sqlparser.sqlstatements.size(); k++) { 6891 createProcedure.getBodyStatements().add(lc_sqlparser.sqlstatements.get(k)); 6892 } 6893 } 6894 } 6895 6896 // fire SQL Statement handle event if set, if return true, stop parsing 6897 if (sqlStatementHandle != null) { 6898 if (sqlStatementHandle.processSQLStatement(sqlstatements.get(i), this)) break; 6899 } 6900 } 6901 6902 if (enableTimeLogging) { 6903 endTime = System.currentTimeMillis(); 6904 parsingTime += (endTime - startTime); 6905 } 6906 6907 if (isPushGloablStack) { 6908 firstFrame.popMeFromStack(getFrameStack()); 6909 } 6910 6911 // 3. start semantic analysis 6912 startTime = enableTimeLogging ? System.currentTimeMillis() : 0; 6913 6914 // Reset resolver2 for each parse 6915 this.resolver2 = null; 6916 6917 // Determine effective resolver type (instance setting takes precedence over TBaseType) 6918 EResolverType effectiveResolverType = this.resolverType; 6919 if (effectiveResolverType == EResolverType.DEFAULT) { 6920 // Fall back to TBaseType settings for backward compatibility 6921 if (TBaseType.isEnableResolver2()) { 6922 effectiveResolverType = EResolverType.RESOLVER2; 6923 } else if (TBaseType.isEnableResolver()) { 6924 effectiveResolverType = EResolverType.RESOLVER; 6925 } else { 6926 effectiveResolverType = EResolverType.NONE; 6927 } 6928 } 6929 6930 // Run the appropriate resolver based on effective type 6931 if (getErrorCount() == 0) { 6932 switch (effectiveResolverType) { 6933 case RESOLVER: 6934 TSQLResolver resolver = new TSQLResolver(globalContext, sqlstatements); 6935 if (!resolver.resolve()) { 6936 // Handle resolution errors 6937 // addErrors(resolver.getLog().getErrors()); 6938 } 6939 break; 6940 6941 case RESOLVER2: 6942 // Use provided config or create default 6943 TSQLResolverConfig config = this.resolver2Config; 6944 if (config == null) { 6945 config = new TSQLResolverConfig(); 6946 } 6947 // Always set vendor on config (needed for vendor-specific resolution like struct-field fallback) 6948 config.setVendor(dbVendor); 6949 // Pass null as globalContext to match original TSQLResolver2 behavior 6950 this.resolver2 = new TSQLResolver2(null, sqlstatements, config); 6951 // Pass sqlEnv to resolver2 for metadata lookup 6952 if (this.sqlEnv != null) { 6953 this.resolver2.setSqlEnv(this.sqlEnv); 6954 } 6955 if (!this.resolver2.resolve()) { 6956 // Handle resolution errors if needed 6957 } 6958 break; 6959 6960 case NONE: 6961 default: 6962 // No resolution 6963 break; 6964 } 6965 } 6966 6967 if (enableTimeLogging) { 6968 endTime = System.currentTimeMillis(); 6969 semanticAnalysisTime += (endTime - startTime); 6970 } 6971 6972 // 4. start interpreter 6973 startTime = enableTimeLogging ? System.currentTimeMillis() : 0; 6974 6975 if ((TBaseType.ENABLE_INTERPRETER) && (getErrorCount() == 0)) { 6976 TLog.clearLogs(); 6977 TGlobalScope globalScope = new TGlobalScope(sqlEnv); 6978 TLog.enableInterpreterLogOnly(); 6979 6980 TASTEvaluator astEvaluator = new TASTEvaluator(this.sqlstatements, globalScope); 6981 astEvaluator.eval(); 6982 } 6983 6984 if (enableTimeLogging) { 6985 endTime = System.currentTimeMillis(); 6986 interpreterTime += (endTime - startTime); 6987 } 6988 6989 return getErrorCount(); 6990 } 6991 6992 6993void copyerrormsg(TCustomSqlStatement sql){ 6994 for (int i = 0; i<sql.getSyntaxErrors().size(); i++){ 6995 this.syntaxErrors.add(new TSyntaxError( (TSyntaxError)sql.getSyntaxErrors().get(i) )); 6996 } 6997// for (int i = 0; i<sql.getSyntaxHints().size(); i++){ 6998// this.syntaxHints.add(new TSyntaxError( (TSyntaxError)sql.getSyntaxHints().get(i) )); 6999// } 7000} 7001 7002private static String calculateLicenseKey(boolean ignoreMachineId){ 7003 7004 if (userName == null) return null; 7005 if (machineId == null) return null; 7006 7007 byte[] bytesOfMessage=null; 7008 String licenseStr = "I love sql pretty printer, yeah!"+userName.toLowerCase(); 7009 if (!ignoreMachineId){ 7010 licenseStr += machineId.toLowerCase(); 7011 } 7012 try { 7013 bytesOfMessage = licenseStr.getBytes("UTF-8"); 7014 } catch (UnsupportedEncodingException e) { 7015 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 7016 } 7017 7018 MessageDigest md = null; 7019 try { 7020 md = MessageDigest.getInstance("MD5"); 7021 } catch (NoSuchAlgorithmException e) { 7022 e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. 7023 } 7024 byte[] digest = md.digest(bytesOfMessage); 7025 7026 return null;//HardwareBinder.getHex(digest); 7027} 7028 7029private static boolean validateLicense(){ 7030 7031 int ret = 0; 7032 return ret == 0; 7033 7034} 7035 7036private static boolean check_license_time(){ 7037 7038 boolean ret = false; 7039 7040 String toDate = TBaseType.license_expired_date; 7041 7042 DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); 7043 Calendar currDtCal = Calendar.getInstance(); 7044 7045 // Zero out the hour, minute, second, and millisecond 7046 currDtCal.set(Calendar.HOUR_OF_DAY, 0); 7047 currDtCal.set(Calendar.MINUTE, 0); 7048 currDtCal.set(Calendar.SECOND, 0); 7049 currDtCal.set(Calendar.MILLISECOND, 0); 7050 7051 Date currDt = currDtCal.getTime(); 7052 7053 Date toDt; 7054 try { 7055 toDt = df.parse(toDate); 7056 } catch (ParseException e) { 7057 toDt = null; 7058 // Print some error message back to the user 7059 } 7060 7061 if (toDt != null){ 7062 int results = toDt.compareTo(currDt); 7063 ret = results > 0; 7064 } 7065 7066 return ret; 7067} 7068 7069 public void setTeradataUtilityType(TeradataUtilityType teradataUtilityType) { 7070 if ((this.getFlexer() != null) && (this.getFlexer() instanceof TLexerTeradata)){ 7071 ((TLexerTeradata)this.getFlexer()).setTeradataUtilityType(teradataUtilityType); 7072 } 7073 } 7074 7075 /** 7076 * Dispose of parser resources and clean up references. 7077 * 7078 * <p>This method releases internal resources used by the parser. 7079 * After calling this method, the parser should not be used further.</p> 7080 * 7081 * <p>If a ManagedSourceBuffer was set, the source text remains in the buffer 7082 * so that tokens can still access it. The user is responsible for calling 7083 * {@link ManagedSourceBuffer#release()} when all tokens are no longer needed.</p> 7084 * 7085 * <p>Note: Tokens created by this parser will remain usable after dispose() 7086 * if a ManagedSourceBuffer was used, as they reference the buffer by ID 7087 * rather than holding direct parser references.</p> 7088 * 7089 * @since 3.1.0.9 7090 */ 7091 public void dispose() { 7092 // Note: We intentionally do NOT remove the source from managed buffer 7093 // This allows tokens to remain usable after parser disposal 7094 // The user must call buffer.release() when done with all tokens 7095 7096 // Clear references to help GC 7097 flexer = null; 7098 fparser = null; 7099 fplsqlparser = null; 7100 finputstream = null; 7101 sqlInputStream = null; 7102 gcurrentsqlstatement = null; 7103 nextStmt = null; 7104 sqlstatements = null; 7105 sourcetokenlist = null; 7106 syntaxErrors = null; 7107 } 7108 7109}