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