001package gudusoft.gsqlparser.nodes;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.scriptWriter.TScriptGenerator;
005import gudusoft.gsqlparser.sqlenv.TSQLEnv;
006import gudusoft.gsqlparser.util.gspMD5Utils;
007
008import java.util.ArrayList;
009import java.util.Iterator;
010
011import static java.nio.charset.StandardCharsets.UTF_8;
012
013/**
014 * This class is the root class for all syntax/parse tree nodes.
015 * A syntax/parse tree node is composed of a sequence of tokens generated by the lexer.
016 * <p>
017 * The syntax node usually includes sub-nodes such as a where clause including expression node.
018 *
019 * <br> Check {@link #getNodeType()} for type of this node.
020 * <br> This node includes all tokens from {@link #getStartToken() start token} and {@link #getEndToken() end token}
021 */
022
023public abstract class TParseTreeNode implements Visitable,Iterator<TSourceToken>{
024
025    public void setEvaluateDatatype(Class<?> evaluateDatatype) {
026        this.evaluateDatatype = evaluateDatatype;
027    }
028
029    /**
030     *  Support String, Integer, Double and Boolean type
031     *
032     * @return
033     */
034    public Class<?> getEvaluateDatatype() {
035        return evaluateDatatype;
036    }
037
038    private Class<?> evaluateDatatype;
039    private Object evalValue;
040
041    public void setEvalValue(Object evalValue) {
042        this.evalValue = evalValue;
043    }
044
045    public Object getEvalValue() {
046        return evalValue;
047    }
048
049    private String plainText = null;
050
051    public void setPlainText(String plainText) {
052        this.plainText = plainText;
053    }
054
055    public String getPlainText() {
056        if (plainText == null){
057            return toString();
058        }else{
059            return plainText;
060        }
061    }
062
063    private ESqlClause location = ESqlClause.unknown;
064
065    public void setLocation(ESqlClause location) {
066        this.location = location;
067    }
068
069    /**
070     * SQL clause that include this objectName such as select list, from clause, set clause
071     *
072     * @return SQL clause that include this objectName
073     */
074    public ESqlClause getLocation() {
075        return location;
076    }
077
078    private String compactString = null;
079
080    /**
081     * representation of this node by removing all spaces, return and comments
082     * @return string representation of this node by removing all spaces, return and comments
083     */
084    public String getCompactString(){
085        if (compactString != null) return compactString;
086
087        StringBuilder sb = new StringBuilder();
088        TSourceToken st = null;
089        currentIterateToken = null;
090        while (this.hasNext()){
091            st = next();
092            if ((st.tokencode == TBaseType.lexspace)||(st.tokencode == TBaseType.lexnewline)
093                    ||(st.tokencode == TBaseType.cmtslashstar)||(st.tokencode == TBaseType.cmtdoublehyphen)
094            ) {
095                continue;
096            }else{
097                sb.append(st.toString());
098            }
099        }
100
101        compactString = sb.toString();
102        return compactString;
103    }
104
105    private String md5 = null;
106    /**
107     *  md5 hash code of the string representation of this node.
108     *  If the string of this node is empty, return the md5 value of the class name of this node.
109     *
110     *  1. remove all spaces, return, comments inside the node<br>
111     *  2. turn number constant in where clause into ? character. <br>
112     *  3. turn string constant in where clause into ?? character. <br>
113     *  4. turn all string of the token into uppercase if it's not a delimited identifier.
114     *
115     * @return md5 hash code of the string representation of this node
116     */
117    public String getMd5(){
118        if (md5 != null) return md5;
119
120        StringBuilder sb = new StringBuilder();
121        TSourceToken st = null;
122        currentIterateToken = null;
123        while (this.hasNext()){
124            st = next();
125            // cmtslashstar lexspace lexnewline cmtdoublehyphen
126            if ((st.tokencode == TBaseType.lexspace)||(st.tokencode == TBaseType.lexnewline)
127                    ||(st.tokencode == TBaseType.cmtslashstar)||(st.tokencode == TBaseType.cmtdoublehyphen)
128            ){
129                continue;
130            } else if ((st.tokencode == TBaseType.fconst)||(st.tokencode == TBaseType.iconst)){
131                if (st.location == ESqlClause.where){
132                    sb.append("?");
133                }else{
134                    sb.append(st.toString());
135                }
136            } else if (st.tokencode == TBaseType.sconst){
137                if (st.location == ESqlClause.where){
138                    sb.append("??");
139                }else{
140                    sb.append(st.toString());
141                }
142            } else if (TSQLEnv.isDelimitedIdentifier(this.dbvendor,st.toString())){
143                sb.append(st.toString());
144            }else {
145                sb.append(st.toString().toUpperCase());
146            }
147        }
148        byte[] md5InBytes;
149        if (sb.toString().length() > 0){
150            md5InBytes = gspMD5Utils.digest(sb.toString().getBytes(UTF_8));
151        }else{
152            md5InBytes = gspMD5Utils.digest(this.getClass().getName() .getBytes(UTF_8));
153        }
154        md5 = gspMD5Utils.bytesToHex(md5InBytes);
155        return md5;
156
157    }
158
159    public TParseTreeNode getParentObjectName() {
160        return parent;
161    }
162
163    public void setParent(TParseTreeNode parent) {
164        this.parent = parent;
165    }
166
167    private TParseTreeNode parent = null;
168
169//    public void  appendAToken(TSourceToken st){
170//        // this token is not belonged to this node
171//        this.getEndToken()
172//    }
173    public static boolean doubleLinkedTokenListToString = true;
174
175//    TSourceToken st = getStartToken();
176//    TSourceToken et = getEndToken();
177    public void insertAfterAToken(TSourceToken anchorToken){
178        if ((anchorToken == null)||(this.getEndToken() == null)||(this.getStartToken() == null) )return;
179        this.getEndToken().setNextTokenInChain(anchorToken.getNextTokenInChain());
180        if (anchorToken.getNextTokenInChain() != null){
181            anchorToken.getNextTokenInChain().setPrevTokenInChain(this.getEndToken());
182        }else{
183            if (anchorToken.getNodesEndWithThisToken().size() > 0){
184                for(Object o:anchorToken.getNodesEndWithThisToken()){
185                    TParseTreeNode node = (TParseTreeNode)o;
186                    node.setEndToken(this.getEndToken());
187                }
188            }
189        }
190        anchorToken.setNextTokenInChain(this.getStartToken());
191        this.getStartToken().setPrevTokenInChain(anchorToken);
192
193    }
194
195   public void insertNewNodeBeforeMe(TParseTreeNode newNode, boolean needCommaBefore){
196
197       updateNodeWithTheSameStartToken(nodeActionInsert,newNode.getStartToken());
198
199       newNode.getStartToken().setPrevTokenInChain(this.getStartToken().getPrevTokenInChain());
200       if (this.getStartToken().getPrevTokenInChain() != null){
201           this.getStartToken().getPrevTokenInChain().setNextTokenInChain(newNode.getStartToken());
202       }
203
204       newNode.getEndToken().setNextTokenInChain(this.getStartToken());
205       this.getStartToken().setPrevTokenInChain(newNode.getEndToken());
206
207       if (needCommaBefore) {
208           TSourceToken commaToken = new TSourceToken(",");
209           newNode.getEndToken().insertANewTokenAfterMe(commaToken);
210       }
211
212   }
213
214   public void appendNewNode(TParseTreeNode newNode, boolean needCommaBefore){
215        // the new node must be share the same parent node with this node
216
217       refreshAllNodesTokenCount();
218       updateMeNodeWithTheSameEndToken(nodeActionAppend,newNode.getEndToken());
219
220       newNode.getEndToken().setNextTokenInChain(this.getEndToken().getNextTokenInChain());
221       if (this.getEndToken().getNextTokenInChain() != null){
222           this.getEndToken().getNextTokenInChain().setPrevTokenInChain(newNode.getEndToken());
223       }
224
225       newNode.getStartToken().setPrevTokenInChain(this.getEndToken());
226       this.getEndToken().setNextTokenInChain(newNode.getStartToken());
227
228       if (needCommaBefore) {
229           TSourceToken commaToken = new TSourceToken(",");
230           this.getEndToken().insertANewTokenAfterMe(commaToken);
231       }
232
233   }
234
235   public void replaceWithNewNode(TParseTreeNode newNode){
236       if ((getStartToken() == null)||(getEndToken() == null)) return;
237       if ((newNode.getStartToken() == null)||(newNode.getEndToken() == null)) return;
238
239       if (getStartToken().getPrevTokenInChain() == null) return;
240
241       refreshAllNodesTokenCount();
242       updateNodeWithTheSameStartToken(nodeActionUpdate,newNode.startToken);
243       updateMeNodeWithTheSameEndToken(nodeActionUpdate,newNode.endToken);
244
245       getStartToken().getPrevTokenInChain().setNextTokenInChain(newNode.getStartToken());
246       newNode.getStartToken().setPrevTokenInChain(getStartToken().getPrevTokenInChain());
247
248       newNode.getEndToken().setNextTokenInChain(getEndToken().getNextTokenInChain());
249       if (getEndToken().getNextTokenInChain() != null){
250           getEndToken().getNextTokenInChain().setPrevTokenInChain(newNode.getEndToken());
251       }
252
253   }
254
255
256
257    TSourceToken currentIterateToken = null;
258
259
260    public void resetIterator(){
261        currentIterateToken = null;
262    }
263
264    @Override
265    public boolean hasNext() {
266        if ((getStartToken() != null)&&(getEndToken() != null)&&(currentIterateToken != getEndToken())){
267            return true;
268        }
269        else{
270            return false;
271        }
272
273    }
274
275    @Override
276    public TSourceToken next() {
277        if (this.hasNext()){
278            if (currentIterateToken == null){
279                currentIterateToken = getStartToken();
280            }else {
281                currentIterateToken = currentIterateToken.getNextTokenInChain();
282            }
283
284            return currentIterateToken;
285        }
286        else
287            return null;
288    }
289
290    @Override
291    public void remove() {
292        throw new UnsupportedOperationException();
293    }
294
295//    @Override
296//    public Iterator<TSourceToken> iterator() {
297//        return new TokenSetIterator();
298//    }
299//
300//    private class TokenSetIterator implements Iterator {
301//        TSourceToken st = getStartToken();
302//        TSourceToken et = getEndToken();
303//        TSourceToken currentToken = null;
304//
305//         public boolean hasNext() {
306//            if ((st != null)&&(et != null)&&(currentToken != et)){
307//                return true;
308//            }
309//            else
310//                return false;
311//        }
312//
313//        public TSourceToken next() {
314//            if (this.hasNext()){
315//                if (currentToken == null){
316//                    currentToken = st;
317//                }else {
318//                    currentToken = currentToken.getNextTokenInChain();
319//                }
320//
321//                return currentToken;
322//            }
323//            else
324//                return null;
325//        }
326//
327//        @Override
328//        public void remove() {
329//
330//        }
331//    }
332
333    public void setNodeStatus(ENodeStatus nodeStatus) {
334        this.nodeStatus = nodeStatus;
335    }
336
337    public ENodeStatus getNodeStatus() {
338
339        return nodeStatus;
340    }
341
342    private ENodeStatus nodeStatus = ENodeStatus.nsNormal;
343
344
345
346    public void addToTokenChain(TSourceToken anchorToken, boolean beforeAnchorToken){
347
348    };
349
350    private int tokenCount = -1;
351
352    public int getTokenCount() {
353        if (tokenCount == -1){
354            calculateTokenCount();
355        }
356        return tokenCount;
357    }
358
359    public void refreshAllNodesTokenCount(){
360        if (this.startToken != null){
361            for(int i=0;i<this.startToken.getNodesStartFromThisToken().size();i++){
362                TParseTreeNode node = this.startToken.getNodesStartFromThisToken().get(i);
363                node.calculateTokenCount();
364            }
365        }
366
367        if (this.endToken != null){
368            for(int i=0;i<this.endToken.getNodesEndWithThisToken().size();i++){
369                TParseTreeNode node = this.endToken.getNodesEndWithThisToken().get(i);
370                node.calculateTokenCount();
371            }
372        }
373
374    }
375
376    public void calculateTokenCount(){
377        int ret = 0;
378        TSourceToken prevst = null;
379        this.resetIterator();
380        while (this.hasNext()){
381            ret++;
382            TSourceToken st = this.next();
383            if (st == null){
384                if (TBaseType.DEBUG){
385                    System.out.println("==========ERROR: start and token is not in the same chain  ===============\n");
386                    System.out.println("Start Token:"+this.getStartToken().toString());
387                    System.out.println("End Token:"+this.getEndToken().toString());
388                    if (prevst != null){
389                        System.out.println("Prev token, code:"+prevst.tokencode+", Text:"+prevst.toString());
390                    }else{
391                        System.out.println("Prev token is null");
392                    }
393                    System.out.println("============================\n");
394                }
395                break;
396            }
397            prevst = st;
398        }
399        this.resetIterator();
400        this.tokenCount = ret;
401    }
402
403    public final static int nodeActionUnknown = 0;
404    public final static int nodeActionRemove = 1;
405    public final static int nodeActionInsert = 2;
406    public final static int nodeActionUpdate = 3;
407    public final static int nodeActionUpdateText = 4;
408    public final static int nodeActionAppend = 5;
409    public final static int nodeChangeStartToken = 6;
410    public final static int nodeChangeEndToken = 7;
411
412    void updateStatusOfNodeShareSameTokens(int nodeAction){
413        TSourceToken startToken = getStartToken();
414        TSourceToken endToken = getEndToken();
415        if (endToken == null) return;
416        if (startToken == null) return;
417
418        // System.out.println("node token count:"+thisNodeTokenCount);
419        this.resetIterator();
420        while(this.hasNext()){
421            TSourceToken st = this.next();
422           // System.out.println(st.toString());
423            if (st == null) break;
424
425            for(int i=0;i<st.getNodesStartFromThisToken().size();i++){
426                TParseTreeNode node = st.getNodesStartFromThisToken().get(i);
427                if (st == startToken){
428                    if (this == node){
429                        switch (nodeAction){
430                            case nodeActionRemove:
431                                node.nodeStatus = ENodeStatus.nsRemoved;
432                                break;
433                            default:
434                                node.nodeStatus = ENodeStatus.nsDetached;
435                                break;
436                        }
437                    }else if (node.getTokenCount() == this.getTokenCount()){
438                        switch (nodeAction){
439                            case nodeActionRemove:
440                                node.nodeStatus = ENodeStatus.nsRemoved;
441                                break;
442                            default:
443                                node.nodeStatus = ENodeStatus.nsDetached;
444                                break;
445                        }
446                    }else if (node.getTokenCount() > this.getTokenCount()){
447                        node.nodeStatus = ENodeStatus.nsPartitial;
448                    }else{
449                        node.nodeStatus = ENodeStatus.nsDetached;
450                    }
451                }else{
452                    node.nodeStatus = ENodeStatus.nsDetached;
453                }
454            }
455
456            for(int i=0;i<st.getNodesEndWithThisToken().size();i++){
457                TParseTreeNode node = st.getNodesEndWithThisToken().get(i);
458                if (st == endToken){
459                    if (this == node){
460                        switch (nodeAction){
461                            case nodeActionRemove:
462                                node.nodeStatus = ENodeStatus.nsRemoved;
463                                break;
464                            default:
465                                node.nodeStatus = ENodeStatus.nsDetached;
466                                break;
467                        }
468                    }else if (node.getTokenCount() == this.getTokenCount()){
469                        switch (nodeAction){
470                            case nodeActionRemove:
471                                node.nodeStatus = ENodeStatus.nsRemoved;
472                                break;
473                            default:
474                                node.nodeStatus = ENodeStatus.nsDetached;
475                                break;
476                        }
477                    }else if (node.getTokenCount() > this.getTokenCount()){
478                        node.nodeStatus = ENodeStatus.nsPartitial;
479                    }else{
480                        switch (nodeAction){
481                            case nodeActionRemove:
482                                node.nodeStatus = ENodeStatus.nsRemoved;
483                                break;
484                            default:
485                                node.nodeStatus = ENodeStatus.nsDetached;
486                                break;
487                        }
488                    }
489                }else{
490                    switch (nodeAction){
491                        case nodeActionRemove:
492                            node.nodeStatus = ENodeStatus.nsRemoved;
493                            break;
494                        default:
495                            node.nodeStatus = ENodeStatus.nsDetached;
496                            break;
497                    }
498                }
499            }
500
501        }
502        this.resetIterator();
503    }
504
505    void updateNodeWithTheSameStartToken(int nodeAction, TSourceToken newStartToken){
506        TSourceToken oldStartToken = this.getStartToken();
507        for(int i=0;i<oldStartToken.getNodesStartFromThisToken().size();i++){
508            TParseTreeNode node = oldStartToken.getNodesStartFromThisToken().get(i);
509            if (node == this){ // myself
510                switch (nodeAction){
511                    case nodeActionRemove:
512                        node.startToken = null;
513                        break;
514                    case nodeActionUpdate:
515                    case nodeActionUpdateText:
516                    case nodeChangeStartToken:
517                        node.startToken = newStartToken;
518                        newStartToken.getNodesStartFromThisToken().push(node);
519                    default:
520                        break;
521                }
522            }else if((node.getTokenCount() == this.getTokenCount())){ // node with same tokens
523                switch (nodeAction){
524                    case nodeActionRemove:
525                        node.startToken = null;
526                        break;
527                    case nodeActionUpdate:
528                    case nodeActionUpdateText:
529                    case nodeChangeStartToken:
530                        node.startToken = newStartToken;
531                        newStartToken.getNodesStartFromThisToken().push(node);
532                    default:
533                        break;
534                }
535            }
536            else if((node.getTokenCount() > this.getTokenCount())) { // parent node
537                node.startToken = newStartToken;
538                newStartToken.getNodesStartFromThisToken().push(node);
539            }else{ // sub node
540
541            }
542        }
543    }
544
545    void updateMeNodeWithTheSameEndToken(int nodeAction, TSourceToken newEndToken){
546        TSourceToken oldEndToken = this.getEndToken();
547        for(int i=0;i<oldEndToken.getNodesEndWithThisToken().size();i++){
548            TParseTreeNode node = oldEndToken.getNodesEndWithThisToken().get(i);
549            if (node == this){ // myself
550                switch (nodeAction){
551                    case nodeActionRemove:
552                        node.endToken = null;
553                        break;
554                    case nodeActionUpdate:
555                    case nodeActionUpdateText:
556                    case nodeChangeEndToken:
557                        node.endToken = newEndToken;
558                        newEndToken.getNodesEndWithThisToken().push(node);
559                    default:
560                        break;
561                }
562            }else if((node.getTokenCount() == this.getTokenCount())){ // node with same tokens
563                switch (nodeAction){
564                    case nodeActionRemove:
565                        node.endToken = null;
566                        break;
567                    case nodeActionUpdate:
568                    case nodeActionUpdateText:
569                    case nodeChangeEndToken:
570                        node.endToken = newEndToken;
571                        newEndToken.getNodesEndWithThisToken().push(node);
572                    default:
573                        break;
574                }
575            }
576            else if((node.getTokenCount() > this.getTokenCount())) { // parent node
577                node.endToken = newEndToken;
578                newEndToken.getNodesEndWithThisToken().push(node);
579            }else{ // sub node
580
581            }
582        }
583    }
584
585    /**
586     * both begin and end token will be removed from the chain
587     *
588     * @param startToken
589     * @param endToken
590     */
591    public static void removeTokensBetweenToken(TSourceToken startToken, TSourceToken endToken){
592       if ((startToken == null)||(endToken == null)) return;
593        startToken.removeFromChain();
594        while (startToken != endToken){
595            startToken = startToken.getNextTokenInChain();
596            if (startToken == null) break;
597            startToken.removeFromChain();
598        }
599    }
600
601    public static void removeTokensBetweenNodes(TParseTreeNode startNode, TParseTreeNode endNode){
602        if ((startNode == null)||(endNode == null)) return;
603        if ((startNode.getEndToken() == null)||(endNode.getStartToken() == null)) return;
604        TSourceToken startToken = startNode.getEndToken().getNextTokenInChain();
605        TSourceToken endToken  = endNode.getStartToken().getPrevTokenInChain();
606        if ((startToken == null)||(endToken == null)) return;
607
608        startToken.removeFromChain();
609        while (startToken != endToken){
610            startToken = startToken.getNextTokenInChain();
611            if (startToken == null) break;
612            startToken.removeFromChain();
613        }
614    }
615
616    public void removeTokens(){
617        if (this.nodeStatus == ENodeStatus.nsRemoved) return;
618
619        TSourceToken oldStartToken = getStartToken();
620        TSourceToken oldEndToken = getEndToken();
621        if (oldEndToken == null) return;
622        if (oldStartToken == null) return;
623
624        refreshAllNodesTokenCount();
625        updateStatusOfNodeShareSameTokens(nodeActionRemove);
626
627        if (oldStartToken.getPrevTokenInChain() != null){
628            updateMeNodeWithTheSameEndToken(nodeActionRemove,oldStartToken.getPrevTokenInChain());
629            oldStartToken.getPrevTokenInChain().setNextTokenInChain(oldEndToken.getNextTokenInChain());
630        }
631        if (oldEndToken.getNextTokenInChain() != null){
632            updateNodeWithTheSameStartToken(nodeActionRemove,oldEndToken.getNextTokenInChain());
633            oldEndToken.getNextTokenInChain().setPrevTokenInChain(oldStartToken.getPrevTokenInChain());
634        }
635
636        if (this.nodeStatus == ENodeStatus.nsNormal){
637            this.nodeStatus = ENodeStatus.nsRemoved;
638        }
639
640        this.setStartTokenDirectly(null);
641        this.setEndTokenDirectly(null);
642
643    }
644
645
646
647    /**
648     * SQL dialect of this statement.
649     */
650    public EDbVendor dbvendor = EDbVendor.dbvgeneric;
651
652    /**
653     * The parser that generate this node.
654     *
655     * @return parser that generate this node
656     */
657    public TGSqlParser getGsqlparser() {
658        if (gsqlparser == null){
659            if (getStartToken() != null){
660                // TODO  removed in 2.6.8.1, to avoid memory leak in TTypeName
661                // gsqlparser = getStartToken().getGsqlparser();
662            }
663        }
664        return gsqlparser;
665    }
666
667    boolean includingComment = true;
668
669
670    public void setIncludingComment(boolean includingComment) {
671        this.includingComment = includingComment;
672    }
673
674    private TGSqlParser gsqlparser = null;
675
676    public void setGsqlparser(TGSqlParser gsqlparser) {
677        this.gsqlparser = gsqlparser;
678        if (gsqlparser != null){
679            this.dbvendor = gsqlparser.getDbVendor();
680        }
681    }
682
683    private int dummyTag = 0;
684
685    public void setDummyTag(int dummyTag) {
686        this.dummyTag = dummyTag;
687    }
688
689    /**
690     * A temporary value can be used for any purposes
691     *
692     * @return a temporary value used for any purposes
693     */
694    public int getDummyTag() {
695        return dummyTag;
696    }
697
698
699    private TSourceToken startToken;
700
701    /**
702     * The first token in this parse tree node
703     *
704     * @return the first token of node
705     */
706    public TSourceToken getStartToken() {
707        return startToken;
708    }
709
710    /**
711     * The last token of the node
712     *
713     * @return the last token of node
714     */
715    public TSourceToken getEndToken() {
716        return endToken;
717    }
718
719    private TSourceToken endToken;
720    private long lineNo = -1;
721
722    /**
723     * Column position of the first token of this node
724     *
725     * @return column position
726     */
727    public long getColumnNo() {
728        if (this.getStartToken() != null){
729            columnNo = this.getStartToken().columnNo;
730        }
731        return columnNo;
732    }
733
734    /**
735     * Line number of the first token of this node
736     *
737     * @return line number
738     */
739    public long getLineNo() {
740        if (this.getStartToken() != null){
741            lineNo = this.getStartToken().lineNo;
742        }
743        return lineNo;
744    }
745
746    private long columnNo = -1;
747
748    private int nodeType;
749    /**
750         * Set the node type for this node.
751         *
752         * @param nodeType The node type.
753         */
754        public void setNodeType(int nodeType)
755        {
756                this.nodeType = nodeType;
757        }
758
759    /**
760     * A unique value to distinguish this node from others
761     *
762     * @return enum value of node type
763     * @see gudusoft.gsqlparser.nodes.ENodeType
764     */
765        public int getNodeType()
766        {
767                return nodeType;
768        }
769
770    String getastext(){ return "";}
771    String getasprettytext(){ return "";}
772
773    /**
774     * Initialize a query tree node.
775     * Used internally
776     *
777     * @param arg1 first argument
778     */
779    public void init(Object arg1)
780    {
781    }
782
783    public void init(Object arg1, Object arg2)
784    {
785    }
786
787    public void init(Object arg1, Object arg2, Object arg3)
788    {
789    }
790
791    public void init(Object arg1, Object arg2, Object arg3, Object arg4)
792    {
793    }
794
795    public void init(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)
796    {
797    }
798
799    public void init(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6)
800    {
801    }
802
803    /**
804     * Analyze the sub-nodes inside this node.
805     * Such as build the relationship between table and column.
806     *
807     * @param psql          SQL statement this node belongs to
808     * @param plocation    SQL clause this node belongs to
809     */
810    public void doParse(TCustomSqlStatement psql, ESqlClause plocation){
811        
812    }
813
814    public void setStartToken(ArrayList startNode) {
815        if (startNode == null) return;
816        if (startNode.size() == 0) return;
817        TParseTreeNode parseTreeNode = (TParseTreeNode)startNode.get(0);
818        this.setStartToken(parseTreeNode.getStartToken());
819    }
820
821    public void setEndToken(ArrayList endNode) {
822        if (endNode == null) return;
823        if (endNode.size() == 0 ) return;
824        TParseTreeNode parseTreeNode = (TParseTreeNode)endNode.get(endNode.size()-1);
825        this.setEndToken(parseTreeNode.getEndToken());
826    }
827
828    public void setStartToken(TSourceToken newStartToken) {
829        if (newStartToken == null) return;
830        TSourceToken oldStartToken = this.startToken;
831        if (oldStartToken != null){
832            if (oldStartToken.getNodesStartFromThisToken().peek() == this){
833                oldStartToken.getNodesStartFromThisToken().pop();
834            }
835        }
836        if (newStartToken.getNodesStartFromThisToken().indexOf(this) == -1)
837        {
838            newStartToken.getNodesStartFromThisToken().push(this);
839        }
840
841        this.startToken = newStartToken;
842    }
843
844    public void setStartToken(TSourceTokenList startTokenList) {
845        if (startTokenList == null) return;
846        this.setStartToken(startTokenList.get(0));
847    }
848
849    public void setStartToken(TParseTreeNode startNode) {
850        if (startNode == null) return;
851        this.setStartToken(startNode.getStartToken());
852    }
853
854    public void setStartTokenDirectly(TSourceToken newStartToken) {
855        this.startToken = newStartToken;
856    }
857    public void setEndTokenDirectly(TSourceToken newEndToken) {
858        this.endToken = newEndToken;
859    }
860
861    public void setEndToken(TSourceToken newEndToken) {
862        if (newEndToken == null) return;
863        TSourceToken oldEndToken = this.getEndToken();
864
865        if (oldEndToken != null){
866            if (oldEndToken.getNodesEndWithThisToken().peek() == this){
867                oldEndToken.getNodesEndWithThisToken().pop();
868            }
869        }
870
871        if (newEndToken.getNodesEndWithThisToken().indexOf(this) == -1){
872            newEndToken.getNodesEndWithThisToken().push(this);
873        }
874
875        this.endToken = newEndToken;
876    }
877
878    public void setEndToken(TSourceTokenList endTokenList) {
879        if (endTokenList == null) return;
880        this.setEndToken(endTokenList.get(endTokenList.size()-1));
881    }
882
883//    public void setEndToken(TParseTreeNodeList endNodeList) {
884//        if (endNodeList == null) return;
885//        this.setEndToken(endNodeList.getEndToken());
886//    }
887
888
889
890    public void setEndToken(TFromTableList endNode) {
891        if (endNode == null) return;
892        this.setEndToken(endNode.getEndToken());
893    }
894
895    public void setEndToken(TParseTreeNode endNode) {
896        if (endNode == null) return;
897        this.setEndToken(endNode.getEndToken());
898    }
899
900    private void setStartTokenToNull(){
901        this.startToken = null;
902    }
903
904    private void setEndTokenToNull(){
905        this.endToken = null;
906    }
907
908    private void resetStartAndEndTokenBeforeRemoveTokens(TSourceTokenList stList, int start, int end,boolean isReplace,TSourceToken relpacedStartToken,TSourceToken replacedEndToken){
909
910        for(int m = start; m<=end;m++){
911            if ((m>stList.size()-1) ||(m<0)) break;
912            TSourceToken deletedToken = stList.get(m);
913            for(int i=0;i<deletedToken.getNodesStartFromThisToken().size();i++){
914                TParseTreeNode node = deletedToken.getNodesStartFromThisToken().get(i);
915                TSourceToken EndSt = node.getEndToken();
916
917                if (isReplace&&((m==start)||(m==end))){
918                    node.setStartToken(relpacedStartToken);
919                }else{
920                    if (EndSt == null){
921                        node.setStartTokenToNull();
922                    }else{
923                        if (EndSt.posinlist > end){
924                            node.setStartToken(stList.get(end+1));
925                        }else if (EndSt.posinlist < start){
926                            node.setStartTokenToNull();
927                            node.setEndTokenToNull();
928                        }else{
929                            node.setStartTokenToNull();
930                            node.setEndTokenToNull();
931                        }
932                    }
933                }
934            } // nodes start from this token
935
936            for (int i=0;i<deletedToken.getNodesEndWithThisToken().size();i++){
937                TParseTreeNode node = deletedToken.getNodesEndWithThisToken().get(i);
938                TSourceToken startSt = node.getStartToken();
939
940                if (isReplace&&((m==start)||(m==end))){
941                    node.setEndToken(replacedEndToken);
942                }else{
943                    if (startSt == null){
944                        node.setEndTokenToNull();
945                    }else{
946                        if (startSt.posinlist > end){
947                            node.setStartTokenToNull();
948                            node.setEndTokenToNull();
949                        }else if (startSt.posinlist < start){
950                            node.setEndToken(stList.get(start - 1));
951                        }else{
952                            node.setStartTokenToNull();
953                            node.setEndTokenToNull();
954                        }
955                    }
956                }
957            }// nodes end with this token
958
959        }//loop all tokens to be deleted in this parse tree nodes
960    }
961
962
963
964    private void fastResetStartAndEndTokenBeforeRemoveTokens(TSourceTokenList stList, int start, int end,TSourceToken replacedToken){
965        int[] startEnd;
966        if (start != end) {
967            startEnd = new int[2];
968            startEnd[0] = start;
969            startEnd[1] = end;
970        }
971        else {
972            startEnd = new int[1];
973            startEnd[0] = start;
974        }
975        for(int m : startEnd){
976            TSourceToken deletedToken = stList.get(m);
977            for(int i=0;i<deletedToken.getNodesStartFromThisToken().size();i++){
978                TParseTreeNode node = deletedToken.getNodesStartFromThisToken().get(i);
979                node.setStartToken(replacedToken);
980            } // nodes start from this token
981
982            for (int i=0;i<deletedToken.getNodesEndWithThisToken().size();i++){
983                TParseTreeNode node = deletedToken.getNodesEndWithThisToken().get(i);
984                node.setEndToken(replacedToken);
985            }// nodes end with this token
986
987        }//loop all tokens to be deleted in this parse tree nodes
988    }
989
990    /**
991     * @deprecated since v1.8.8.0, use scriptWriter technology to modify the node
992     * Set the new string text of a node will destroy all the sub-node structure
993     *
994     * @param sqlSegment that override original text of this node.
995     */
996
997    /*
998     * <p>1. new string will be tokenized into a list of source tokens: stlist
999     * <p>2. link alternativetoken of start token of this node to the first token in stlist generated in step 1.
1000     * <p>3. link back alternative token of last token in stlist to the last token of this node.
1001     * <p>So, if you find a start token of parse tree node has an alternativetoken, then text of this node should be modified by using setString(String sqlSegment)
1002     * <p> if a parse tree node with an alias clause like: tablename as tablealias,
1003     * <p> TTable.setString() will replace whole text "tablename as tablealias" including alias clause.
1004     *
1005     * steps to set new string(sqlSegment) of parse tree node
1006     * length(sqlSegment)=0 or sqlSegment = one space,, means remove this node from parse tree
1007     * length(sqlSegment) > 0 , means replace source tokens of this node with new tokens
1008     *
1009     */
1010    public void setString2(String sqlSegment){
1011
1012//        TGSqlParser l_sqlparser = new TGSqlParser(getGsqlparser().getDbVendor());
1013//        l_sqlparser.sqltext =  sqlSegment;
1014//        l_sqlparser.tokenizeSqltext();
1015
1016        TSingletonParser singletonParser = TSingletonParser.getInstance();
1017
1018        TSourceTokenList stList;
1019        if (this.dbvendor == EDbVendor.dbvgeneric){
1020            stList = singletonParser.getTokens(TGSqlParser.currentDBVendor,sqlSegment);
1021        }else{
1022            stList = singletonParser.getTokens(this.dbvendor,sqlSegment);
1023        }
1024
1025
1026
1027        if ((getStartToken() == null)&&(getEndToken() == null)){
1028            // this is a manually created parse tree node, not created by yacc
1029//            l_sqlparser.sourcetokenlist.get(0).container = l_sqlparser.sourcetokenlist;
1030//            l_sqlparser.sourcetokenlist.get(l_sqlparser.sourcetokenlist.size()-1).container = l_sqlparser.sourcetokenlist;
1031            setStartToken(stList.get(0));
1032            setEndToken(stList.get(stList.size()-1));
1033            return;
1034        }
1035
1036        TSourceToken lcStartToken = getStartToken();
1037        TSourceToken lcEndToken = getEndToken();
1038
1039       // TSourceTokenList stList = lcEndToken.container;
1040
1041        int lcStartTokenPos = lcStartToken.posinlist;
1042        int lcEndTokenPos = lcEndToken.posinlist;
1043
1044
1045        if ((sqlSegment.length()==0) || (sqlSegment == " ")){
1046
1047           //reset start and end token of those parse tree node
1048            resetStartAndEndTokenBeforeRemoveTokens(stList, lcStartTokenPos, lcEndTokenPos,false,null,null);
1049
1050            // remove token from list
1051            for(int i=lcEndTokenPos;i>=lcStartTokenPos;i--){
1052                stList.remove(i);
1053            }
1054
1055            // reindex posinlist after remove token from container
1056            for(int i=lcStartTokenPos;i<stList.size();i++){
1057                stList.get(i).posinlist = i;
1058            }
1059
1060        }else{
1061            //replace
1062           //reset start and end token of those parse tree node
1063            TSourceToken lcReplacedStartToken = stList.get(0);
1064            TSourceToken lcReplacedEndToken = stList.get(stList.size()-1);
1065            resetStartAndEndTokenBeforeRemoveTokens(stList, lcStartTokenPos, lcEndTokenPos,true,lcReplacedStartToken,lcReplacedEndToken);
1066
1067            // remove token from list
1068            for(int i=lcEndTokenPos;i>=lcStartTokenPos;i--){
1069                stList.remove(i);
1070            }
1071
1072
1073//            for(int i = stList.size()-1; i>=0; i--){
1074//                TSourceToken st = stList.get(i);
1075//                st.container = stList;
1076//                stList.add(lcStartTokenPos,st);
1077//            }
1078
1079            // reindex posinlist after remove token from container
1080            for(int i=lcStartTokenPos;i<stList.size();i++){
1081                TSourceToken st = stList.get(i);
1082                st.posinlist =  i;
1083            }
1084
1085        }
1086
1087    }
1088
1089    /**
1090     * Set the text of the node and update the corresponding source tokens synchronously.
1091     * This way, when the toString() method of the node itself or its parent node is called,
1092     * it will return the modified text.
1093     *
1094     * @param sqlSegment
1095     */
1096    public void setString(String sqlSegment){
1097        if (doubleLinkedTokenListToString){
1098            setText(sqlSegment);
1099        }else{
1100            setString2(sqlSegment);
1101        }
1102    }
1103
1104    public void fastSetString(String sqlSegment){
1105
1106        TSourceToken replaceToken = new TSourceToken(sqlSegment);
1107        setText(replaceToken, replaceToken);
1108    }
1109
1110
1111    /**
1112     * return null if no comment is found before this node.
1113     *
1114     * @return the comment before this node
1115     */
1116    public String getCommentBeforeNode(){
1117        String ret = null;
1118        TSourceToken lcStartToken;
1119
1120        if (doubleLinkedTokenListToString){
1121            lcStartToken = getStartToken();
1122            if (lcStartToken ==  null) return null;
1123
1124            TSourceToken lcCurrentToken = lcStartToken.getPrevTokenInChain();
1125            while (lcCurrentToken != null){
1126                if ((lcCurrentToken.tokentype == ETokenType.ttreturn)||(lcCurrentToken.tokentype == ETokenType.ttwhitespace))
1127                {
1128                    if (ret != null){
1129                        ret = lcCurrentToken.toString() + ret ;
1130                    }
1131                    lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1132                    continue;
1133                }
1134                else if (lcCurrentToken.astext.trim().length() == 0) {
1135                    lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1136                    continue;
1137                }
1138                if ((lcCurrentToken.tokencode == TBaseType.cmtslashstar) ||(lcCurrentToken.tokencode == TBaseType.cmtdoublehyphen)
1139                        || lcCurrentToken.astext.startsWith("--") || lcCurrentToken.astext.startsWith("/*")
1140                ){
1141                    if (ret == null){
1142                        ret = lcCurrentToken.toString();
1143                    }else{
1144                        ret = lcCurrentToken.toString()+ ret;
1145                    }
1146
1147                    lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1148                    continue;
1149                }
1150
1151                break;
1152            }
1153        }else{
1154            lcStartToken = getStartToken();
1155            if (lcStartToken ==  null) return null;
1156
1157            TSourceTokenList stList = lcStartToken.container;
1158            if (stList == null) return null;
1159
1160            int b = lcStartToken.posinlist;
1161
1162            for(int i = b - 1 ; i>=0;i--){
1163                TSourceToken st = stList.get(i);
1164                if ((st.tokencode == TBaseType.lexspace)|| (st.tokencode == TBaseType.lexnewline)) continue;
1165                if (st.astext.trim().length() == 0) continue;
1166                if ((st.tokencode == TBaseType.cmtslashstar) ||(st.tokencode == TBaseType.cmtdoublehyphen)){
1167                    if (ret == null){
1168                        ret = st.toString();
1169                    }else{
1170                        ret = st.toString()+TBaseType.newline + ret;
1171                    }
1172                    continue;
1173                }
1174                else if (st.astext.startsWith("--") || st.astext.startsWith("/*")){
1175                    if (ret == null){
1176                        ret = st.toString();
1177                    }else{
1178                        ret = st.toString()+TBaseType.newline + ret;
1179                    }
1180                    continue;
1181                }
1182                break;
1183            }
1184        }
1185
1186        return ret;
1187    }
1188
1189    public String getCommentAfterNode(){
1190        String ret = null;
1191        TSourceToken lcEndToken;
1192
1193        if (!doubleLinkedTokenListToString) return ret;
1194
1195        lcEndToken = getEndToken();
1196        if (lcEndToken ==  null) return null;
1197
1198        TSourceToken lcCurrentToken = lcEndToken;
1199        while (lcCurrentToken != null){
1200            if ((lcCurrentToken.tokentype == ETokenType.ttreturn)||(lcCurrentToken.tokentype == ETokenType.ttwhitespace))
1201            {
1202                if (ret != null){
1203                    ret = lcCurrentToken.toString() + ret ;
1204                }
1205                lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1206                continue;
1207            }
1208            else if (lcCurrentToken.astext.trim().length() == 0) {
1209                lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1210                continue;
1211            }
1212            if ((lcCurrentToken.tokencode == TBaseType.cmtslashstar) ||(lcCurrentToken.tokencode == TBaseType.cmtdoublehyphen)
1213                    || lcCurrentToken.astext.startsWith("--") || lcCurrentToken.astext.startsWith("/*")
1214            ){
1215                if (ret == null){
1216                    ret = lcCurrentToken.toString();
1217                }else{
1218                    ret =  lcCurrentToken.toString()  +ret ;
1219                }
1220
1221                lcCurrentToken = lcCurrentToken.getPrevTokenInChain();
1222                continue;
1223            }
1224
1225            break;
1226        }
1227
1228            return ret.trim(); // 移调第一个space or return token if any
1229
1230    }
1231
1232    /**
1233     * String representation of this parse tree node.
1234     * <p>
1235     * This string was generated by collecting text from the start token of this node to the end token of this node.
1236     * If this node was modified, then use {@link #toScript()} to get string representation of this node.
1237     *
1238     * @return string representation of this parse tree node
1239     */
1240    public String toString2(){
1241        String ret = null;
1242        TSourceToken lcStartToken = getStartToken();
1243        if (lcStartToken ==  null) return null;
1244
1245        TSourceToken lcEndToken = getEndToken();
1246        if (lcEndToken ==  null) return null;
1247
1248        TSourceTokenList stList = lcStartToken.container;
1249        if (stList == null) return null;
1250
1251        int b = lcStartToken.posinlist;
1252        int e = lcEndToken.posinlist;
1253
1254        StringBuffer sb = new StringBuffer("");
1255
1256        for(int i= b ; i<=e;i++){
1257              if(!includingComment && ((stList.get(i).tokencode == TBaseType.cmtslashstar) ||(stList.get(i).tokencode == TBaseType.cmtdoublehyphen))){
1258                  continue;
1259              }
1260            sb.append(stList.get(i).toString());
1261        }
1262
1263        return sb.toString();
1264    }
1265
1266    /**
1267     * The returned text is formed by concatenating the source tokens contained in this node one by one.
1268     *
1269     * @return
1270     */
1271    public String toString(){
1272        if (doubleLinkedTokenListToString){
1273            String ret = null;
1274            TSourceToken lcStartToken = getStartToken();
1275            if (lcStartToken ==  null) return null;
1276            TSourceToken lcEndToken = getEndToken();
1277            if (lcEndToken ==  null) return null;
1278
1279            boolean chainUnchanged = true;
1280
1281            StringBuffer sb = new StringBuffer("");
1282            TSourceToken lcPrevSt = null;
1283            boolean ignoreNextReturnToken = false, isChainModified = false;
1284
1285            TSourceToken lcCurrentToken = lcStartToken;
1286            while (lcCurrentToken != null){
1287                if (lcCurrentToken.tokentype == ETokenType.ttreturn){
1288                    if (ignoreNextReturnToken && (isChainModified||((lcPrevSt != null)&&(lcCurrentToken.posinlist - lcPrevSt.posinlist != 1))) ){
1289                        lcCurrentToken.tokenstatus = ETokenStatus.tsdeleted;
1290                        //System.out.println("Find deleted token:"+lcCurrentToken.astext);
1291                    }else{
1292                        ignoreNextReturnToken = true;
1293                    }
1294                }else if (lcCurrentToken.tokentype != ETokenType.ttwhitespace){
1295                    ignoreNextReturnToken = false;
1296                }
1297                if (!isChainModified && lcPrevSt != null){
1298                    isChainModified = (lcCurrentToken.posinlist - lcPrevSt.posinlist != 1);
1299
1300                    if (isChainModified){
1301                        //System.out.println("token chain changed");
1302                    }
1303                }
1304                lcPrevSt = lcCurrentToken;
1305
1306                if (lcCurrentToken.equals(lcEndToken)){
1307                    break;
1308                }else{
1309                    lcCurrentToken = lcCurrentToken.getNextTokenInChain();
1310                }
1311            }
1312
1313            lcCurrentToken = lcStartToken;
1314            while (lcCurrentToken != null){
1315                if((lcCurrentToken.tokenstatus == ETokenStatus.tsdeleted)
1316                        ||(!includingComment  && ((lcCurrentToken.tokencode == TBaseType.cmtslashstar) ||(lcCurrentToken.tokencode == TBaseType.cmtdoublehyphen)))
1317                ){
1318                    // ignore this token, do nothing
1319                   // System.out.println("out: ignore deleted token:"+lcCurrentToken.astext);
1320                }else{
1321                    //
1322                        sb.append(lcCurrentToken.toString());
1323                }
1324
1325                if (lcCurrentToken.equals(lcEndToken)){
1326                    break;
1327                }else{
1328                    lcCurrentToken = lcCurrentToken.getNextTokenInChain();
1329                }
1330            }
1331
1332            return sb.toString();
1333
1334        }else
1335        {
1336            return toString2();
1337        }
1338    }
1339
1340
1341    void setText(String nodeText, EDbVendor dbVendor){
1342        this.dbvendor = dbVendor;
1343        setText(nodeText);
1344    }
1345
1346    private boolean tokensInChain = true;
1347
1348    public boolean isTokensInChain() {
1349        return tokensInChain;
1350    }
1351
1352    void setText(TSourceToken startToken, TSourceToken endToken){
1353        TSourceToken newStartToken = startToken;
1354        TSourceToken newEndToken = endToken;
1355
1356        TSourceToken oldStartToken = getStartToken();
1357        TSourceToken oldEndToken = getEndToken();
1358        tokensInChain = false;
1359        if ((oldStartToken == null)||(oldEndToken == null)){
1360            setStartToken(newStartToken);
1361            setEndToken(newEndToken);
1362            nodeStatus = ENodeStatus.nsFlattened;
1363            return;
1364        }
1365
1366        refreshAllNodesTokenCount();
1367
1368        updateStatusOfNodeShareSameTokens(nodeActionUpdateText);
1369
1370        updateNodeWithTheSameStartToken(nodeActionUpdateText,newStartToken);
1371        updateMeNodeWithTheSameEndToken(nodeActionUpdateText,newEndToken);
1372
1373        if (oldStartToken.getPrevTokenInChain() != null){
1374            oldStartToken.getPrevTokenInChain().setNextTokenInChain(newStartToken);
1375            newStartToken.setPrevTokenInChain(oldStartToken.getPrevTokenInChain());
1376        }
1377
1378        if (oldEndToken.getNextTokenInChain() != null){
1379            oldEndToken.getNextTokenInChain().setPrevTokenInChain(newEndToken);
1380            newEndToken.setNextTokenInChain(oldEndToken.getNextTokenInChain());
1381        }
1382
1383        tokensInChain = true;
1384    }
1385    /**
1386     * set text of this node, if the original token of this node
1387     * is in a token chain, then merge the new token into the chain as well.
1388     *
1389     * use double linked list
1390     *
1391     * @param nodeText node text
1392     */
1393    void setText(String nodeText){
1394        if ((this.getNodeStatus() == ENodeStatus.nsRemoved)||(nodeText.length() == 0)) return;
1395       // if ((nodeText.length() == 0)) return;
1396
1397//        TGSqlParser sqlParser = new TGSqlParser(TGSqlParser.currentDBVendor);
1398//        sqlParser.sqltext = nodeText;
1399//        sqlParser.tokenizeSqltext();
1400//        TSourceToken newStartToken = sqlParser.getSourcetokenlist().get(0);
1401//        TSourceToken newEndToken = sqlParser.getSourcetokenlist().get(sqlParser.getSourcetokenlist().size() - 1);
1402//        setText(newStartToken, newEndToken);
1403
1404        TSingletonParser singletonParser = TSingletonParser.getInstance();
1405
1406        TSourceTokenList stList;
1407        if (this.dbvendor == EDbVendor.dbvgeneric){
1408            stList = singletonParser.getTokens(TGSqlParser.currentDBVendor,nodeText);
1409        }else{
1410            stList = singletonParser.getTokens(this.dbvendor,nodeText);
1411        }
1412
1413
1414        TSourceToken newStartToken = stList.get(0);
1415        TSourceToken newEndToken = stList.get(stList.size() - 1);
1416        setText(newStartToken, newEndToken);
1417
1418    }
1419
1420
1421    /**
1422     * @deprecated since v1.8.8.0, use scriptWriter technology to modify the node
1423     * Inserts tokens(from start token to end token ) of this parse tree node at the specified position in this
1424     * list. Shifts the element currently at that position (if any) and
1425     * any subsequent elements to the right .
1426
1427     * @param targetList the new list of source tokens
1428     * @param index  the position insert the targetList
1429     * @return length of the source token list after insert targetList
1430     */
1431     public int addAllMyTokensToTokenList(TSourceTokenList targetList, int index){
1432       int ret = -1;
1433
1434        TSourceToken lcStartToken = getStartToken();
1435        if (lcStartToken ==  null) return ret;
1436
1437        TSourceToken lcEndToken = getEndToken();
1438        if (lcEndToken ==  null) return ret;
1439
1440        TSourceTokenList stList = lcStartToken.container;
1441        if (stList == null) return ret;
1442
1443        for(int i=lcEndToken.posinlist;i>=lcStartToken.posinlist;i--){
1444            targetList.add(index,stList.get(i));
1445            stList.get(i).container = targetList;
1446        }
1447
1448        // reindex posinlist after remove token from container
1449        for(int i=index;i<targetList.size();i++){
1450            targetList.get(i).posinlist = i;
1451        }
1452
1453        return lcEndToken.posinlist - lcStartToken.posinlist + 1;
1454    }
1455
1456    /**
1457     * @deprecated since v1.8.8.0, use scriptWriter technology to modify the node
1458     *
1459     * @param additionalToken usually was comma before or after this parse tree node that also need to be deleted
1460     * @return length of the source token list after remove tokens
1461     */
1462    protected int removeAllMyTokensFromTokenList(TSourceToken additionalToken){
1463
1464        int ret = -1;
1465        TSourceToken lcStartToken = getStartToken();
1466        if (lcStartToken ==  null) return ret;
1467        int lcStartTokenPos = lcStartToken.posinlist;
1468
1469
1470        TSourceToken lcEndToken = getEndToken();
1471        if (lcEndToken ==  null) return ret;
1472        int lcEndTokenPos = lcEndToken.posinlist;
1473
1474
1475        TSourceTokenList stList = lcStartToken.container;
1476        if (stList == null) return ret;
1477
1478        if ((additionalToken != null)&&(additionalToken.tokentype != ETokenType.ttRemoved)){
1479            if (additionalToken.posinlist < lcStartTokenPos){
1480                lcStartTokenPos = additionalToken.posinlist;
1481                additionalToken.tokentype = ETokenType.ttRemoved;
1482            }else if(additionalToken.posinlist > lcEndTokenPos){
1483                lcEndTokenPos = additionalToken.posinlist;
1484                additionalToken.tokentype = ETokenType.ttRemoved;
1485            }
1486        }
1487
1488       //reset start and end token of those parse tree node
1489        resetStartAndEndTokenBeforeRemoveTokens(stList, lcStartTokenPos, lcEndTokenPos,false,null,null);
1490
1491        // remove token from list
1492        for(int i=lcEndTokenPos;i>=lcStartTokenPos;i--){
1493            if ((i>stList.size()-1) ||(i<0)) break;
1494            stList.remove(i);
1495        }
1496
1497        // reindex posinlist after remove token from container
1498        for(int i=lcStartTokenPos;i<stList.size();i++){
1499            if ((i>stList.size()-1) ||(i<0)) break;
1500            stList.get(i).posinlist = i;
1501        }
1502
1503        return lcStartTokenPos - lcEndTokenPos +1;
1504    }
1505
1506    /**
1507     * @deprecated since v1.8.8.0, use scriptWriter technology to modify the node
1508     * parse string to tokens, then add those tokens to the end of this parse tree node
1509     *
1510     * @param sqlSegment
1511     */
1512//    protected void appendString(String sqlSegment){
1513//
1514//        if (sqlSegment.length() == 0) return;
1515//        if (getStartToken() == null) return;
1516//        if (getEndToken() == null) return;
1517//
1518//        TSourceToken lcEndToken = getEndToken();
1519//
1520//        TSourceTokenList stList = lcEndToken.container;
1521//
1522//        int lcEndTokenPos = lcEndToken.posinlist;
1523//
1524////        TGSqlParser l_sqlparser = new TGSqlParser(getGsqlparser().getDbVendor());
1525////        l_sqlparser.sqltext =  sqlSegment;
1526//
1527//        TGSqlParser l_sqlparser;
1528//        if (this.dbvendor == EDbVendor.dbvgeneric){
1529//            l_sqlparser = TGSqlParser.getSingletonParser(getGsqlparser().getDbVendor());
1530//        }else{
1531//            l_sqlparser = TGSqlParser.getSingletonParser(this.dbvendor);
1532//        }
1533//
1534//        synchronized(this) {
1535//            l_sqlparser.tokenizeSqltext();
1536//            if (l_sqlparser.sourcetokenlist.size() == 0) return;
1537//            TSourceToken endTokenOfNewSourceTokenList = l_sqlparser.sourcetokenlist.get(l_sqlparser.sourcetokenlist.size()-1);
1538//
1539//            for(int i = l_sqlparser.sourcetokenlist.size()-1; i>=0; i--){
1540//                TSourceToken st = l_sqlparser.sourcetokenlist.get(i);
1541//                st.container = stList;
1542//                stList.add(lcEndTokenPos+1,st);
1543//            }
1544//
1545//            // reindex posinlist after remove token from container
1546//            for(int i=lcEndTokenPos+1;i<stList.size();i++){
1547//               stList.get(i).posinlist =  i;
1548//            }
1549//
1550//            for(int i=0;i<lcEndToken.getNodesEndWithThisToken().size();i++){
1551//                TParseTreeNode node = lcEndToken.getNodesEndWithThisToken().get(i);
1552//                node.setEndToken(endTokenOfNewSourceTokenList);
1553//            }
1554//        }
1555//
1556//}
1557
1558    /**
1559     * Accept a visitor
1560     *
1561     * @param v visitor is a descendant class of {@link TParseTreeVisitor}
1562     */
1563  public void accept(TParseTreeVisitor v)
1564  {
1565
1566  }
1567
1568    /**
1569     * Accept a visitor to iterate this class and sub-nodes of this class
1570     *
1571     * @param v visitor is a descendant class of {@link TParseTreeVisitor}
1572     */
1573    public void acceptChildren(TParseTreeVisitor v)
1574    {
1575
1576    }
1577
1578  private TScriptGenerator scriptGenerator = null;
1579
1580    /**
1581     * Return the text string of this node, the return value is the same as {@link #toString()} if this node is not modified manually
1582     * after created by parser.
1583     * <br>
1584     * If this node is modified, then use this method to get string representation instead of the {@link #toString()} method.
1585     *
1586     * @return text string of this node
1587     */
1588  public String toScript(){
1589    if (scriptGenerator == null){
1590        scriptGenerator = new TScriptGenerator();
1591    }
1592     return scriptGenerator.generateScript(this);
1593  }
1594
1595  public void setChanged(){
1596      // set the changed status to the first token of this node
1597      if (getStartToken() == null) return;
1598      getStartToken().setTokenstatus(ETokenStatus.tschanged);
1599  }
1600
1601    /**
1602     * Detect wether this node is modified by checking all tokens included in this node.
1603     * @return true if this node is modified.
1604     */
1605  public boolean isChanged(){
1606      boolean ret = false;
1607      TSourceToken lcStartToken = getStartToken();
1608      if (lcStartToken ==  null) return ret;
1609
1610      TSourceToken lcEndToken = getEndToken();
1611      if (lcEndToken ==  null) return ret;
1612
1613      TSourceTokenList stList = lcStartToken.container;
1614      if (stList == null) return ret;
1615
1616      int b = lcStartToken.posinlist;
1617      int e = lcEndToken.posinlist;
1618
1619      for(int i= b ; i<=e;i++){
1620          if (stList.get(i).getTokenstatus() == ETokenStatus.tschanged){
1621              ret = true;
1622              break;
1623          }
1624      }
1625      return ret;
1626  }
1627
1628    protected void doAppendNewNode( TParseTreeNode newNode, TParseTreeNode anchorNode,boolean needCommaBefore){
1629        if (anchorNode != null){
1630            anchorNode.appendNewNode(newNode,needCommaBefore);
1631        }else{
1632            if (!newNode.isTokensInChain()){
1633                this.appendNewNode(newNode,false);
1634                this.setEndToken(newNode.getEndToken());
1635            }
1636        }
1637    }
1638
1639    private TParseTreeNode anchorNode = null;
1640
1641    public void setAnchorNode(TParseTreeNode anchorNode) {
1642        this.anchorNode = anchorNode;
1643    }
1644
1645    public TParseTreeNode getAnchorNode() {
1646        return anchorNode;
1647    }
1648
1649  public void setNewSubNode( TParseTreeNode oldSubNode, TParseTreeNode newSubNode,TParseTreeNode anchorNode){
1650      if (newSubNode == null){
1651          //remove the old node
1652          if (oldSubNode != null){
1653              oldSubNode.removeTokens();
1654          }
1655      }else {
1656          if (oldSubNode == null){
1657              // add a total new where clause, we need to find an anchor
1658              if (newSubNode.getNodeStatus()!=ENodeStatus.nsNormal){
1659                  doAppendNewNode(newSubNode,anchorNode,false);
1660              }
1661
1662          }else{
1663              //replace old where clause
1664              if (newSubNode.getNodeStatus()!=ENodeStatus.nsNormal){
1665                  oldSubNode.replaceWithNewNode(newSubNode);
1666              }
1667          }
1668      }
1669  }
1670
1671    public static boolean subNodeInNode(TParseTreeNode subNode, TParseTreeNode wholeNode){
1672        if (wholeNode == null) return false;
1673        TSourceToken startToken = wholeNode.getStartToken();
1674        if (startToken == null) return false;
1675        TSourceToken endToken = wholeNode.getEndToken();
1676        if (endToken == null) return false;
1677
1678        TSourceToken startTokenOfSubNode = subNode.getStartToken();
1679        if (startTokenOfSubNode == null) return false;
1680        if (startTokenOfSubNode.lineNo < startToken.lineNo) return false;
1681        if ((startTokenOfSubNode.lineNo == startToken.lineNo) && (startTokenOfSubNode.columnNo < startToken.columnNo)) return false;
1682
1683        TSourceToken endTokenOfSubNode = subNode.getEndToken();
1684        if (endTokenOfSubNode == null) return false;
1685
1686        if (endTokenOfSubNode.lineNo > endToken.lineNo) return false;
1687        if ((endTokenOfSubNode.lineNo == endToken.lineNo)&&(endTokenOfSubNode.columnNo > endToken.columnNo)) return false;
1688
1689        return true;
1690    }
1691
1692//  public int setText(EDbVendor dbVendor, String sqlText){
1693//      TGSqlParser sqlParser = new TGSqlParser(dbvendor);
1694//      sqlParser.sqltext = sqlText;
1695//      sqlParser.tokenizeSqltext();
1696//
1697//  }
1698
1699}
1700