001package gudusoft.gsqlparser; 002 003import gudusoft.gsqlparser.nodes.TObjectName; 004import gudusoft.gsqlparser.nodes.TParseTreeNode; 005 006import java.util.Stack; 007 008/** 009 * Represents a source token which is the basic syntactic unit of SQL. 010 * A token can be a key word, an identifier, a quoted identifier, a literal (or constant), or a special character symbol. 011 * Tokens are normally separated by whitespace (space, tab, newline), but need not be if there is no ambiguity 012 * (which is generally only the case if a special character is adjacent to some other token type). 013 * <p> 014 * The parse tree node consists of source tokens. 015 * <p> 016 * <br>A list of source token will be available after parse or tokenize the input SQL. 017 * <pre> 018 * {@code 019 * 020 * TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvoracle); 021 * sqlparser.sqltext = "select col from t"; 022 * int ret = sqlparser.parse(); 023 * if (ret == 0){ 024 * for(int i=0;i<sqlparser.sourcetokenlist.size();i++){ 025 * TSourceToken st = sqlparser.sourcetokenlist.get(i); 026 * System.out.println(st.tokentype.toString()+" "+st.toString()); 027 * } 028 * }else{ 029 * System.out.println(sqlparser.getErrormessage()); 030 * } 031 * 032 * } 033 * </pre> 034 * Get a list of source tokens after call the method {@link gudusoft.gsqlparser.TGSqlParser#parse() } 035 * or just call {@link gudusoft.gsqlparser.TGSqlParser#tokenizeSqltext()} if you only 036 * need to access tokens of input SQL without generating the full parse tree. 037 * <br><br> 038 * {@link #tokencode} is the unique id represents the type of token, 039 * some typical tokens are: whitespace, return, keyword, identifier. This value is mainly used by the parser internally. 040 * <p> 041 * {@link #tokentype} uniquely identify the token type in a more meaningful way. It's more easier to use 042 * this field in your program than tokencode. 043 */ 044 045public class TSourceToken implements Cloneable { 046 047 public TSourceToken clone(){ 048 TSourceToken cloneObject = new TSourceToken(); 049 cloneObject.tokencode = this.tokencode; 050 cloneObject.tokenstatus = this.tokenstatus; 051 cloneObject.tokentype = this.tokentype; 052 cloneObject.dbObjectType = this.dbObjectType; 053 cloneObject.setAstext(this.getAstext()); 054 cloneObject.lineNo = this.lineNo; 055 cloneObject.columnNo = this.columnNo; 056 057 return cloneObject; 058 } 059 060 public ESqlClause location = ESqlClause.unknown; 061 062 public static void concatInChain(TSourceToken st1, TSourceToken st2){ 063 st1.setNextTokenInChain(st2); 064 st2.setPrevTokenInChain(st1); 065 } 066 067 public void insertANewTokenAfterMe(TSourceToken newToken){ 068 newToken.setNextTokenInChain(this.getNextTokenInChain()); 069 if (this.getNextTokenInChain() != null){ 070 this.getNextTokenInChain().setPrevTokenInChain(newToken); 071 } 072 073 newToken.setPrevTokenInChain(this); 074 this.setNextTokenInChain(newToken); 075 } 076 077 public void insertANewTokenBeforeMe(TSourceToken newToken){ 078 newToken.setPrevTokenInChain(this.getPrevTokenInChain()); 079 if (this.getPrevTokenInChain() != null){ 080 this.getPrevTokenInChain().setNextTokenInChain(newToken); 081 } 082 083 newToken.setNextTokenInChain(this); 084 this.setPrevTokenInChain(newToken); 085 } 086 087 public void updateNodeEndWithThisToken(){ 088 for(int i=0;i<this.getNodesEndWithThisToken().size();i++){ 089 TParseTreeNode node = this.getNodesEndWithThisToken().get(i); 090 if (this.getPrevTokenInChain() != null){ 091 node.setEndTokenDirectly(this.getPrevTokenInChain()); 092 this.getPrevTokenInChain().getNodesEndWithThisToken().push(node); 093 } 094 } 095 } 096 097 public void updateNodeStartWithThisToken(){ 098 for(int i=0;i<this.getNodesStartFromThisToken().size();i++){ 099 TParseTreeNode node = this.getNodesStartFromThisToken().get(i); 100 if (this.getNextTokenInChain() != null){ 101 node.setStartTokenDirectly(this.getNextTokenInChain()); 102 this.getNextTokenInChain().getNodesStartFromThisToken().push(node); 103 } 104 } 105 } 106 107 public void removeFromChain(){ 108 if (this.getPrevTokenInChain() != null){ 109 this.getPrevTokenInChain().setNextTokenInChain(this.getNextTokenInChain()); 110 if (this.getNextTokenInChain() != null){ 111 this.getNextTokenInChain().setPrevTokenInChain(this.getPrevTokenInChain()); 112 } 113 } 114 } 115 private TSourceToken prevTokenInChain = null, nextTokenInChain = null; 116 117 public void setPrevTokenInChain(TSourceToken prevTokenInChain) { 118 this.prevTokenInChain = prevTokenInChain; 119 } 120 121 public void setNextTokenInChain(TSourceToken nextTokenInChain) { 122 this.nextTokenInChain = nextTokenInChain; 123 } 124 125 public TSourceToken getPrevTokenInChain() { 126 return prevTokenInChain; 127 } 128 129 public TSourceToken getNextTokenInChain() { 130 return nextTokenInChain; 131 } 132 133 public ETokenStatus getTokenstatus() { 134 return tokenstatus; 135 } 136 137 public int getQuoteSymbolLength(){ 138 String pstr = this.toString(); 139 if (pstr.startsWith("'")){ 140 return 1; 141 }else if (pstr.startsWith("$")){ 142 return this.dolqstart.length(); 143 }else { 144 return 0; 145 } 146 } 147 public String getQuotedString(){ 148 String pstr = this.toString(); 149 if (pstr.startsWith("'")){ 150 return pstr.substring(1,pstr.length()-1); 151 }else if (pstr.startsWith("$")){ 152 return pstr.substring(this.dolqstart.length(),pstr.length()- this.dolqstart.length()); 153 }else { 154 return ""; 155 } 156 } 157 158 /** 159 * String literal in SQL usually inside ``. 160 * Quoted identifier in SQL usually surrounded by [ and ], 161 * This method only returns the text inside those surroundings. 162 * 163 * @return text inside `` and [] 164 */ 165 public String getTextWithoutQuoted(){ 166 if ((toString().startsWith("'"))||(toString().startsWith("["))||(toString().startsWith("\""))){ 167 return toString().substring(1, toString().length() - 1); 168 }else 169 return toString(); 170 } 171 172 /** 173 * Class constructor 174 */ 175 public TSourceToken(){ 176 } 177 178 /** 179 * Class constructor, set a string value. 180 * 181 * @param s the string value this toke represent for. 182 */ 183 public TSourceToken(String s){ 184 setAstext(s); 185 } 186 187 /** 188 * The string text of this token 189 * 190 * @return the string text of this token 191 */ 192 public String toScript(){ 193 return getAstext(); 194 } 195 196 197 public int prevTokenCode = 0; 198 /** 199 * Unique id of this token used by parser internally. 200 * check available value start from {@link gudusoft.gsqlparser.TBaseType#cmtslashstar} 201 */ 202 public int tokencode; 203 204 /** 205 * the line number of the first character in this token 206 */ 207 public long lineNo; 208 209 /** 210 * the column number of the first character in this token 211 */ 212 public long columnNo; 213 214 /** 215 * Token's offset from the beginning of the input query. 216 * <pre> 217 * {@code 218 * public void testOffset(){ 219 * TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvoracle); 220 * sqlparser.sqltext = "select f from t\n" + 221 * "where f>1\n"; 222 * assertTrue(sqlparser.parse() == 0); 223 * for (int i=0;i<sqlparser.sourcetokenlist.size();i++){ 224 * TSourceToken st = sqlparser.sourcetokenlist.get(i); 225 * String textFromOffset = sqlparser.sqltext.toString().substring((int)st.offset,(int)st.offset+st.toString().length()); 226 * assertTrue(st.toString().equalsIgnoreCase(textFromOffset)); 227 * } 228 * } 229 * } 230 * </pre> 231 */ 232 public long offset; 233 234 /** 235 * Uniquely identify the token type in a more meaningful way. It's more easier to use 236 * this field in your program than tokencode. 237 * check available value in {@link gudusoft.gsqlparser.ETokenType ETokenType} 238 */ 239 public ETokenType tokentype; 240 241 /** 242 * Container for this token which is a list of source token, this is the reference to {@link gudusoft.gsqlparser.TGSqlParser#sourcetokenlist} 243 */ 244 public TSourceTokenList container; 245 246 /** 247 * When a vendor tokenizer replaces one source token by several (BigQuery 248 * splits {@code `project.dataset.table`} into {@code `project` . `dataset` . `table`} 249 * so the grammar sees the parts), every generated token points here at the 250 * token it was split from; {@code null} for ordinary tokens. Consumers that 251 * must reproduce the user's spelling (the SQL formatter) print the original 252 * once for the whole run instead of the parts. 253 * 254 * @since 4.2.9 255 */ 256 public TSourceToken splitFrom; 257 258 /** 259 * Index of this token in the {@link #container}, start from 0 260 * 261 * <pre> 262 * {@code 263 * public void testPosinList(){ 264 * TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvoracle); 265 * sqlparser.sqltext = "select f from t\n" + 266 * "where f>1\n"; 267 * assertTrue(sqlparser.parse() == 0); 268 * for (int i=0;i<sqlparser.sourcetokenlist.size();i++){ 269 * assertTrue(i == sqlparser.sourcetokenlist.get(i).posinlist); 270 * } 271 * } 272 * } 273 * </pre> 274 */ 275 public int posinlist; 276 277 /** 278 * The text content of this token. 279 * 280 * <p>This public field is maintained for backwards compatibility with existing code. 281 * New code should use getter/setter methods instead of direct field access.</p> 282 * 283 * <h3>Recommended Usage:</h3> 284 * <ul> 285 * <li><b>Reading text:</b> Use {@link #toString()} method</li> 286 * <li><b>Writing text:</b> Use {@link #setAstext(String)} method</li> 287 * </ul> 288 * 289 * @see #toString() - Safe way to read token text 290 * @see #getAstext() - Alternative getter method 291 * @see #setAstext(String) - Proper way to set token text 292 * @since 1.0 (public field maintained for backwards compatibility) 293 */ 294 public String astext; 295 296 public void appendText(TSourceToken st){ 297 298 if (this.toString().startsWith(".")){ 299 // dataset_id.3_ST_LEAK_ORDERS, .3_ST_LEAK_ORDERS 是由 .3 和_ST_LEAK_ORDERS组成 300 // 在拼接 .3 和_ST_LEAK_ORDERS 时,需要把 .3 中的 . 去掉 301 this.setAstext(this.toString().substring(1,this.toString().length())); 302 this.insertANewTokenBeforeMe(new TSourceToken(".")); 303 } 304 if (st.toString().endsWith(".")){ 305 this.setAstext(this.getAstext() +st.toString().substring(0,st.toString().length()-1)); 306 //st.tokenstatus = ETokenStatus.tsdeleted; // make sure this token don't appear in toString() 307 308 // 以下代码确保 920778. 后面的 . 在 TObjectName.toString() 中出现 309 // prod-gcp-data-lakehouse-920778.EXTERNALDATA.SMS_LOCATION 310 311 st.tokencode = '.'; 312 st.setAstext("."); 313 st.tokentype = ETokenType.ttperiod; 314 }else{ 315 this.setAstext(this.getAstext() +st.toString()); 316 st.tokenstatus = ETokenStatus.tsdeleted; 317 } 318 } 319 320 public void appendText(String text){ 321 this.setAstext(this.getAstext() +text); 322 } 323 324 public void insertText(TSourceToken st){ 325 this.setAstext(st.toString()+ this.getAstext()); 326 st.tokenstatus = ETokenStatus.tsdeleted; 327 } 328 public void setTextWithBackup(String newText){ 329 330 prevsourcecode = getAstext(); 331 tag = TBaseType.tag_token_value_changed_in_on_canonical; 332 333 setAstext(newText); 334 } 335 336 public boolean isChangedInAsCanonical(){ 337 return tag == TBaseType.tag_token_value_changed_in_on_canonical; 338 } 339 340 public void setTokenstatus(ETokenStatus tokenstatus) { 341 this.tokenstatus = tokenstatus; 342 } 343 344 // private ETokenStatus statusForRewrite = ETokenStatus.tsoriginal; 345 346 /** 347 * Maintenance the status of this token during lex and parsing. 348 * Used by the parser internally. 349 */ 350 public ETokenStatus tokenstatus; 351 352 /** 353 * Start part of Dollar-quoted String Constants of PostgreSQL. 354 * 355 * While the standard syntax for specifying string constants is usually convenient, 356 * it can be difficult to understand when the desired string contains many single quotes or backslashes, 357 * since each of those must be doubled. To allow more readable queries in such situations, 358 * PostgreSQL provides another way, called "dollar quoting", to write string constants. 359 * A dollar-quoted string constant consists of a dollar sign ($), an optional "tag" of zero or more characters, 360 * another dollar sign, an arbitrary sequence of characters that makes up the string content, a dollar sign, 361 * the same tag that began this dollar quote, and a dollar sign. 362 * <p></p> 363 * For example, here are two different ways to specify the string "Dianne's horse" using dollar quoting: 364 * <pre> 365 * $$Dianne's horse$$ 366 * $SomeTag$Dianne's horse$SomeTag$ 367 * </pre> 368 * 369 * This field will return $$ and $SomeTag$ accordingly. 370 */ 371 public String dolqstart;//postgresql, start part of Dollar-quoted String Constants 372 373 private String prevsourcecode; 374 375 public void restoreText(){ 376 setAstext(prevsourcecode); 377 tag = 0; 378 } 379 380 public boolean insqlpluscmd; 381 382 /* 383 * source token can be end token of one or more parse tree nodes 384 * NodesEndWithThisToken includes all those parse tree nodes 385 */ 386 private Stack<TParseTreeNode> NodesEndWithThisToken = null; 387 388 /** 389 * 390 * 391 * A list of nodes whose end token is this token. 392 * 393 * @return A list of nodes whose end token is this token. 394 */ 395 public Stack<TParseTreeNode> getNodesEndWithThisToken() { 396 if (this.NodesEndWithThisToken == null){ 397 this.NodesEndWithThisToken = new Stack<TParseTreeNode>(); 398 } 399 return NodesEndWithThisToken; 400 } 401 402 /* 403 * source token can be start token of one or more parse tree nodes, 404 * NodesStartFromThisToken includes those parse tree nodes. 405 */ 406 private Stack<TParseTreeNode> NodesStartFromThisToken = null; 407 408 /** 409 * 410 * A list of node whose start token is this token 411 * 412 * @return A list of node whose start token is this token 413 */ 414 public Stack<TParseTreeNode> getNodesStartFromThisToken() { 415 if (this.NodesStartFromThisToken == null){ 416 this.NodesStartFromThisToken = new Stack<TParseTreeNode>(); 417 } 418 return NodesStartFromThisToken; 419 } 420 421 422 /** 423 * SQL statement that owns this token. 424 */ 425 public TCustomSqlStatement stmt; 426 427 /** 428 * Space to save a value for temporary use 429 */ 430 public int tag; 431 432 /** 433 * @deprecated use {@link #setDbObjectType} instead. 434 * 435 * @param dbObjType the database object type 436 */ 437 public void setDbObjType(int dbObjType) { 438 this.dbObjType = dbObjType; 439 } 440 441 /** 442 * Token in a {@link TObjectName} has the same database object type as the objectName. 443 * Please use {@link gudusoft.gsqlparser.nodes.TObjectName#getDbObjectType} instead of this method if possible. 444 * 445 * @return the type of the database object 446 */ 447 public int getDbObjType() { 448 449 return dbObjType; 450 } 451 452 /** 453 * Set the database object type of this token 454 * 455 * @param dbObjectType database object type 456 */ 457 public void setDbObjectType(EDbObjectType dbObjectType) { 458 this.dbObjectType = dbObjectType; 459 } 460 461 /** 462 * Token in a {@link TObjectName} has the same database object type as the objectName. 463 * Please use {@link gudusoft.gsqlparser.nodes.TObjectName#getDbObjectType} instead of this method if possible. 464 * 465 * @return the type of the database object 466 */ 467 public EDbObjectType getDbObjectType() { 468 469 return dbObjectType; 470 } 471 472 private EDbObjectType dbObjectType = EDbObjectType.unknown; 473 private int dbObjType = TObjectName.ttobjUnknown; 474 475 476 477 /** 478 * The database vendor which the SQL script includes this token will run against 479 * 480 * @param dbvendor the database vendor such as Oracle, DB2 and so on. 481 */ 482 public void setDbvendor(EDbVendor dbvendor) { 483 this.dbvendor = dbvendor; 484 } 485 486 /** 487 * The database vendor which the SQL script includes this token will run against 488 * @return dbvendor the database vendor such as Oracle, DB2 and so on. 489 */ 490 public EDbVendor getDbvendor() { 491 492 return dbvendor; 493 } 494 495 private EDbVendor dbvendor; 496 497 /** 498 * set new string of this token 499 * 500 * @param str the new string text 501 */ 502 public void setString(String str){ 503 setAstext(str); 504 } 505 506 /** 507 * The original string text for this token. 508 * @return the string text 509 */ 510 public String toString(){ 511 return astext != null ? astext : ""; 512 } 513 514 515 516 /** 517 * String text with the debug information such as coordinate, token code, token type 518 * 519 * @return the string value with full debug info 520 */ 521 public String toStringDebug(){ 522 String ret = lineNo +","+ columnNo +","+ getAstext().length()+","+offset+","+tokencode+" "+tokentype; 523 if (tokencode == TBaseType.cmtslashstar) 524 {ret = ret +" multi line comment";} 525 else if (tokencode == TBaseType.cmtdoublehyphen) 526 {ret = ret +" single line comment";} 527 else if (tokencode == TBaseType.lexspace) 528 {ret = ret +" space"; } 529 else if (tokencode == TBaseType.lexnewline) 530 {ret = ret +" newline"; } 531 else 532 {ret = ret +" "+ getAstext();} 533 return ret; 534 } 535 536 /** 537 * Space, return, comments are treated as non-solid token by default 538 * 539 * @param tokentype token type 540 * @return true if token type is not one of ttwhitespace,ttreturn,ttsimplecomment,ttbracketedcomment 541 */ 542 public static boolean isnonsolidtoken(ETokenType tokentype){ 543 return ( (tokentype == ETokenType.ttwhitespace) || (tokentype == ETokenType.ttreturn) 544 ||(tokentype == ETokenType.ttsimplecomment)||(tokentype == ETokenType.ttbracketedcomment)); 545 } 546 547 /** 548 * Is this token a solid token or not. 549 * 550 * @return true if it's a non-solid token. 551 */ 552 public boolean isnonsolidtoken(){ 553 return !issolidtoken(); 554 } 555 556 /** 557 * Is this token a non-solid token or not. 558 * 559 * @return true if it's a solid token. 560 */ 561 public boolean issolidtoken(){ 562 return !isnonsolidtoken(this.tokentype); 563 } 564 565 private TSourceTokenList tokensBefore = null; 566 private TSourceTokenList tokensAfter = null; 567 568 /** 569 * Used in sql formatter package only. 570 * 571 * @return source token list 572 */ 573 public TSourceTokenList getTokensAfter() { 574 if (this.tokensAfter == null){ 575 this.tokensAfter = new TSourceTokenList(); 576 } 577 return tokensAfter; 578 } 579 580 /** 581 * Used in sql formatter package only 582 * 583 * @return source token list 584 */ 585 public TSourceTokenList getTokensBefore() { 586 if (this.tokensBefore == null){ 587 this.tokensBefore = new TSourceTokenList(); 588 } 589 return tokensBefore; 590 } 591 592 private TSourceToken replaceToken = null; 593 594 /** 595 * Used in sql formatter package only 596 * 597 * @param replaceToken replaced token 598 */ 599 public void setReplaceToken(TSourceToken replaceToken) { 600 this.replaceToken = replaceToken; 601 } 602 603 /** 604 * Used in sql formatter package only 605 * 606 * @return replaced token 607 */ 608 public TSourceToken getReplaceToken() { 609 610 return replaceToken; 611 } 612 613 public TSourceToken nextToken(){ 614 TSourceToken ret = null; 615 if (this.container == null) return ret; 616 if (this.posinlist >= this.container.size() - 1) return null; 617 return this.container.get(this.posinlist+1); 618 } 619 620 621 public TSourceToken searchTokenAtTheEndOfSameLine(){ 622 TSourceToken ret = null; 623 if (this.container == null) return ret; 624 int i = this.container.searchLastTokenAtTheSameLine(this.posinlist); 625 if (i == -1) return null; 626 return this.container.get(i); 627 } 628 /** 629 * Search a token before or after this token in the same source token list. 630 * The result token should has the tokencode equals to the targetTokenCode 631 * in a specified range. 632 * 633 * @param targetTokenCode, the token code need to be searched 634 * @param range, > 0, search token start from the next token and forward, 635 * = 0, just compare with this token, 636 * < 0, search from the previous token and backword. 637 * @return the token with the same token code, otherwise, return null. 638 */ 639 public TSourceToken searchToken(int targetTokenCode,int range, int stopTokenCode, boolean stopAtSemiColon){ 640 TSourceToken ret = null; 641 if (this.container == null) return ret; 642 return this.container.searchToken(targetTokenCode,"",this,range,stopTokenCode,stopAtSemiColon); 643 } 644 645 public TSourceToken searchToken(int targetTokenCode,int range){ 646 return searchToken(targetTokenCode,range,0,false); 647 } 648 649 /** 650 * Search a token before or after this token in the same source token list. 651 * The result token should has the string text equals to the targetTokenText 652 * in a specified range. 653 * 654 * @param targetTokenText, the target string text 655 * @param range, > 0, search token start from the next token and forward, 656 * = 0, just compare with this token, 657 * < 0, search from the previous token and backword. 658 * @return the token with the same token code, otherwise, return null. 659 */ 660 public TSourceToken searchToken(String targetTokenText,int range, int stopTokenCode, boolean stopAtSemiColon){ 661 TSourceToken ret = null; 662 if (this.container == null) return ret; 663 return this.container.searchToken(0,targetTokenText,this,range,stopTokenCode,stopAtSemiColon); 664 } 665 666 public TSourceToken searchToken(String targetTokenText,int range) { 667 return searchToken(targetTokenText,range,0,false); 668 } 669 /** 670 * Search the first non-solid token after the next objectName. 671 * <p></p> 672 * Take this SQL for example: 673 * <pre> 674 * return new scott.func(x1); 675 * </pre> 676 * If this token is <code>new</code>, then call searchTokenAfterObjectName will return <code>(</code> token. 677 * 678 * @return solid token after the next objectName 679 */ 680 public TSourceToken searchTokenAfterObjectName(){ 681 TSourceToken ret = null; 682 if (this.container == null) return ret; 683 int i = container.nextObjectNameToken(posinlist,1,false); 684 if (i == -1) return ret; 685 return container.get(i).nextSolidToken(); 686 } 687 688 public TSourceToken nextSolidToken(int pstep){ 689 TSourceToken ret = null; 690 if (this.container == null) return ret; 691 return this.container.nextsolidtoken(this,pstep,false); 692 } 693 694 695 /** 696 * The next token whose {@link #tokentype} is not ttreturn,ttwhitespace,ttsimplecomment and ttbracketedcomment. 697 * 698 * @return the next solid token, returns null if not found. 699 */ 700 public TSourceToken nextSolidToken(){ 701 TSourceToken ret = null; 702 if (this.container == null) return ret; 703 return this.container.nextsolidtoken(this,1,false); 704 } 705 706 /** 707 * The next token whose {@link #tokentype} is not ttreturn,ttwhitespace,ttsimplecomment and ttbracketedcomment. 708 * 709 * @param treatCommentAsSolidToken, set to true will treat comment token as a solid token 710 * @return the solid token if found, otherwise, return null 711 */ 712 public TSourceToken nextSolidToken(boolean treatCommentAsSolidToken){ 713 TSourceToken ret = null; 714 if (this.container == null) return ret; 715 return this.container.nextsolidtoken(this,1,treatCommentAsSolidToken); 716 } 717 718 719 /** 720 * The previous token whose {@link #tokentype} is not ttreturn,ttwhitespace,ttsimplecomment and ttbracketedcomment. 721 * 722 * @return the solid token if found, otherwise, return null 723 */ 724 public TSourceToken prevSolidToken(){ 725 TSourceToken ret = null; 726 if (this.container == null) return ret; 727 return this.container.nextsolidtoken(this,-1,false); 728 } 729 730 /** 731 * The previous token whose {@link #tokentype} is not ttreturn,ttwhitespace,ttsimplecomment and ttbracketedcomment 732 * 733 * @param treatCommentAsSolidToken set to true will treat comment token as a solid token 734 * @return the solid token if found, otherwise, return null 735 */ 736 public TSourceToken prevSolidToken(boolean treatCommentAsSolidToken){ 737 TSourceToken ret = null; 738 if (this.container == null) return ret; 739 return this.container.nextsolidtoken(this,-1,treatCommentAsSolidToken); 740 } 741 742 /** 743 * Check to see if this token is the first token in a line of the input SQL 744 * 745 * @return true if this is the first token of a line, otherwise, return false 746 */ 747 public boolean isFirstTokenOfLine(){ 748 TSourceToken st = prevSolidToken(); 749 if (st == null) return true; 750 return (st.lineNo != this.lineNo); 751 } 752 753 /** 754 * Check to see if this token is the last token of in a line in the input SQL 755 * 756 * @return true if this is the last token of a line, otherwise, return false 757 */ 758 public boolean isLastTokenOfLine(){ 759 TSourceToken st = nextSolidToken(); 760 if (st == null) return true; 761 return (st.lineNo != this.lineNo); 762 } 763 764 765 private TSourceToken linkToken = null; 766 767 /** 768 * Create a link between two tokens. Make it easy to access another linked token. 769 * Usually, those are two tokens like the parenthesis in this SQL: <code>(select * from t)</code> 770 * 771 * @param linkToken the token need to be linked 772 */ 773 public void setLinkToken(TSourceToken linkToken) { 774 this.linkToken = linkToken; 775 linkToken.linkToken = this; 776 } 777 778 /** 779 * Gets the linked token. 780 * Take this SQL for example: 781 * <code>(select * from t)</code>, if this token is '(', then you call this method will return ')' token. 782 * 783 * @return the paired parenthesis in select, expression 784 */ 785 public TSourceToken getLinkToken() { 786 787 return linkToken; 788 } 789 790 /** 791 * Remove double quote <code>""</code>, bracket quote <code>[]</code> , left/right brace <code>{}</code> 792 * from a delimited identifier and return string text of this identifier. 793 * 794 * @return string text of this token 795 * 796 * @deprecated since 2.5.3.4 797 */ 798 public String toUnQuotedString(){ 799 if ((tokentype == ETokenType.ttdqstring) 800 ||(tokentype == ETokenType.ttdbstring) 801 ||(tokentype == ETokenType.ttbrstring) 802 ){ 803 return toString().substring(1,toString().length() - 1); 804 }else if ((dbvendor == EDbVendor.dbvmysql)&&(toString().startsWith("`"))){ 805 return toString().substring(1,toString().length() - 1); 806 }else { 807 return toString(); 808 } 809 } 810 811 /** 812 * Text representation for this token. 813 */ 814 public String getAstext() { 815 return toString(); //astext; 816 } 817 818 public void setAstext(String astext) { 819 this.astext = astext; 820 } 821}