001package gudusoft.gsqlparser.stmt;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.TStmtScope;
005import gudusoft.gsqlparser.nodes.*;
006import gudusoft.gsqlparser.nodes.hana.TTimeTravel;
007import gudusoft.gsqlparser.nodes.hive.*;
008import gudusoft.gsqlparser.nodes.mssql.TOptionClause;
009import gudusoft.gsqlparser.nodes.THierarchical;
010import gudusoft.gsqlparser.nodes.teradata.TExpandOnClause;
011import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType;
012import gudusoft.gsqlparser.sqlenv.IdentifierService;
013import gudusoft.gsqlparser.sqlenv.TSQLEnv;
014import gudusoft.gsqlparser.sqlenv.TSQLTable;
015
016import java.util.ArrayList;
017import java.util.Collections;
018import java.util.TreeMap;
019
020
021/**
022 * Class {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement } represents query specification, query expression and select statement.
023 * <br><br><b>query specification</b> including following clause:
024 * <ul>
025 *     <li>select list {@link #getResultColumnList}</li>
026 *     <li>from clause {@link #joins}</li>
027 *     <li>where clause {@link #getWhereClause}</li>
028 *     <li>group clause {@link #getGroupByClause}</li>
029 *     <li>having clause {@link #getGroupByClause}</li>
030 * </ul>
031 * In some databases, query specification also known as sub-select.
032 *
033 * <br><br><b>query expression</b> including all elements in query specification and following clause:
034 * <ul>
035 *     <li>order by clause {@link #getOrderbyClause}</li>
036 *     <li>offset clause {@link #getOffsetClause}</li>
037 *     <li>for clause</li>
038 * </ul>
039 * In some databases, query expression also known as full-select.
040 * <br>It is a component of the select-statement, the INSERT statement, and the CREATE VIEW statement.
041 * And a full-select that is enclosed in parentheses is sometimes called a sub-query.
042 *
043 * <br><br>select statement including all elements in query expression and following clause:
044 * <ul>
045 *     <li>compute clause {@link #getComputeClause}</li>
046 *     <li>for update clause {@link #getForUpdateClause}</li>
047 *     <li>optimizer hint</li>
048 *     <li>ctes {@link #getCteList}</li>
049 * </ul>
050 * Lots of clauses on this level are db vendors specific.
051 *
052
053 * <br><br>
054 * Use {@link #isCombinedQuery} to check whether UNION, EXCEPT and INTERSECT operators is used.
055 * If returns true, use {@link #getLeftStmt} and {@link #getRightStmt} to get query expression.
056 * You need to check {@link #isCombinedQuery} recursively, all clauses of {@link gudusoft.gsqlparser.stmt.TSelectSqlStatement}
057 * only available when this function returns false.
058 *
059 */
060
061public class TSelectSqlStatement extends TCustomSqlStatement {
062
063    // 如果是 combined query, 并且当前select 没有预先设定的 endToken, 则取最右边 query 的 endToken
064    public TSourceToken getEndToken() {
065        if (super.getEndToken() != null) return super.getEndToken();
066        if (this.isCombinedQuery()){
067            return this.getRightStmt().getEndToken();
068        }else{
069            return super.getEndToken();
070        }
071    }
072
073    public void setSubQueryInFromClauseCanUseParentSelectAsEnclosingScope(boolean subQueryInFromClauseCanUseParentSelectAsEnclosingScope) {
074        this.subQueryInFromClauseCanUseParentSelectAsEnclosingScope = subQueryInFromClauseCanUseParentSelectAsEnclosingScope;
075    }
076
077    public boolean isSubQueryInFromClauseCanUseParentSelectAsEnclosingScope() {
078        return subQueryInFromClauseCanUseParentSelectAsEnclosingScope;
079    }
080
081    private boolean subQueryInFromClauseCanUseParentSelectAsEnclosingScope = false;
082
083    boolean starColumnPushedDown = false;
084
085    public boolean isStarColumnPushedDown() {
086        return starColumnPushedDown;
087    }
088
089    public void setStarColumnPushedDown(boolean starColumnPushedDown) {
090        this.starColumnPushedDown = starColumnPushedDown;
091    }
092
093    // StarRocks pipe operator support
094    private TPTNodeList<TParseTreeNode> pipeOperators;
095    private boolean isPipeQuery = false;
096
097    // Oracle 12c WITH FUNCTION/PROCEDURE support - inline PL/SQL definitions
098    private TStatementListSqlNode withPlsqlItems;
099
100    /**
101     * Get the inline PL/SQL function/procedure definitions from WITH clause.
102     * Oracle 12c+ allows defining PL/SQL functions inline in the WITH clause:
103     * WITH FUNCTION f(x NUMBER) RETURN NUMBER IS BEGIN RETURN x*2; END;
104     * SELECT f(1) FROM dual
105     *
106     * @return list of inline function/procedure definitions, or null if none
107     */
108    public TStatementListSqlNode getWithPlsqlItems() {
109        return withPlsqlItems;
110    }
111
112    /**
113     * Set the inline PL/SQL function/procedure definitions.
114     * @param withPlsqlItems list of inline function/procedure definitions
115     */
116    public void setWithPlsqlItems(TStatementListSqlNode withPlsqlItems) {
117        this.withPlsqlItems = withPlsqlItems;
118    }
119
120    /**
121     * Get the list of pipe operators for StarRocks pipe query syntax.
122     * Pipe queries use the |> operator to chain operations:
123     * FROM table |> SELECT * |> WHERE cond |> ORDER BY col
124     *
125     * @return list of TPipeOperator nodes, or null if not a pipe query
126     */
127    public TPTNodeList<TParseTreeNode> getPipeOperators() {
128        return pipeOperators;
129    }
130
131    /**
132     * Set the pipe operators list.
133     * @param pipeOperators list of pipe operator nodes
134     */
135    public void setPipeOperators(TPTNodeList<TParseTreeNode> pipeOperators) {
136        this.pipeOperators = pipeOperators;
137    }
138
139    /**
140     * Check if this is a StarRocks pipe query.
141     * Pipe queries use the syntax: FROM table |> SELECT * |> WHERE ...
142     *
143     * @return true if this is a pipe query
144     */
145    public boolean isPipeQuery() {
146        return isPipeQuery;
147    }
148
149    /**
150     * Set whether this is a pipe query.
151     * @param isPipeQuery true if this is a pipe query
152     */
153    public void setIsPipeQuery(boolean isPipeQuery) {
154        this.isPipeQuery = isPipeQuery;
155    }
156
157    /**
158     * 在 sql script 中,和该 relation 关联的 attribute。
159     * select a from t;
160     * attribute a 就是 relation t 的 referenceAttribute, 如果没有 metadata and ddl,
161     * relation t 的 getAttributes() 应该可以推断出包含 a, 但 t 是否还包含其他的 attribute 就无从得知。
162     */
163
164    @Override
165    public ArrayList<TAttributeNode> getAttributes(){
166        if (this.getFromClause() == null) return null;
167
168        return this.getFromClause().getAttributes();
169
170//        relationAttributes.clear();
171//        for(TTable table:getRelations()){
172//            relationAttributes.addAll(table.getAttributes());
173//        }
174//
175//        if (relationAttributes.size() > 0){
176//            TBaseType.log ("relationAttributes.size() in select is :"+relationAttributes.size()
177//                    +", relation size: "+getRelations().size()
178//                    +", relation 0 type:"+getRelations().get(0).getTableType()
179//                    ,1);
180//            // System.out.println(this.toString());
181//        }
182//
183//        return relationAttributes;
184    }
185
186    ArrayList<TAttributeNode> relationAttributes = new ArrayList<>();
187
188//    private TExpression skipOffset;
189//    private TExpression firstMax;
190//    private TExpression limitMax;
191//
192//    public void setSkipOffset(TExpression skipOffset) {
193//        this.skipOffset = skipOffset;
194//    }
195//
196//    public void setFirstMax(TExpression firstMax) {
197//        this.firstMax = firstMax;
198//    }
199//
200//    public void setLimitMax(TExpression limitMax) {
201//        this.limitMax = limitMax;
202//    }
203//
204//    /**
205//     * Informix skip offset
206//     * @return skip offset
207//     */
208//    public TExpression getSkipOffset() {
209//
210//        return skipOffset;
211//    }
212//
213//    /**
214//     * Informix first Max
215//     * @return first Max
216//     */
217//    public TExpression getFirstMax() {
218//        return firstMax;
219//    }
220//
221//    /**
222//     * Informix limit max
223//     * @return limit max
224//     */
225//    public TExpression getLimitMax() {
226//        return limitMax;
227//    }
228
229    private ArrayList<TSelectSqlStatement> multiSelectStatements;
230
231    /**
232     * Hive, from ... select, select,...
233     * <br> Multiple select statement in Hive from query syntax
234     *
235     * @return Multiple select statement in Hive from query syntax
236     */
237    public ArrayList<TSelectSqlStatement> getMultiSelectStatements() {
238        if(multiSelectStatements == null){
239            multiSelectStatements = new ArrayList<>();
240        }
241        return multiSelectStatements;
242    }
243
244    private TClusterBy clusterBy;
245
246    public void setClusterBy(TClusterBy clusterBy) {
247        this.clusterBy = clusterBy;
248    }
249
250    public TClusterBy getClusterBy() {
251        return clusterBy;
252    }
253
254    private boolean isConsume;
255
256    public void setConsume(boolean consume) {
257        isConsume = consume;
258    }
259
260    public boolean isConsume() {
261        return isConsume;
262    }
263
264    private TStatementList hiveBodyList = null;
265
266    /**
267     * @deprecated since 2.6.3.5, please use {@link #getMultiSelectStatements()} to retrieve
268     * multimple select statement in Hive from query ... select, select, ...
269     *
270     * @return
271     */
272    public TStatementList getHiveBodyList() {
273        if (hiveBodyList == null)
274            hiveBodyList = new TStatementList();
275        return hiveBodyList;
276    }
277
278    public void setSelectModifiers(ArrayList<TSelectModifier> selectModifiers) {
279        this.selectModifiers = selectModifiers;
280    }
281
282    public ArrayList<TSelectModifier> getSelectModifiers() {
283        return selectModifiers;
284    }
285
286    private ArrayList<TSelectModifier> selectModifiers;
287
288
289    private TTimeTravel timeTravel; // hana
290    private THintClause hintClause; //hana
291
292    public void setTimeTravel(TTimeTravel timeTravel) {
293        setNewSubNode(this.timeTravel,timeTravel,getAnchorNode());
294        this.timeTravel = timeTravel;
295    }
296
297    public void setHintClause(THintClause hintClause) {
298        setNewSubNode(this.hintClause,hintClause,getAnchorNode());
299        this.hintClause = hintClause;
300    }
301
302
303    public TTimeTravel getTimeTravel() {
304
305        return timeTravel;
306    }
307
308    public THintClause getHintClause() {
309        return hintClause;
310    }
311
312    private int parenthesisCount = 0;
313    private int parenthesisCountBeforeOrder = 0;
314
315    public void setFetchFirstClause(TFetchFirstClause fetchFirstClause) {
316        setNewSubNode(this.fetchFirstClause,fetchFirstClause,getAnchorNode());
317        this.fetchFirstClause = fetchFirstClause;
318    }
319
320
321    public void setParenthesisCount(int parenthesisCount) {
322        this.parenthesisCount = parenthesisCount;
323    }
324
325    public void setParenthesisCountBeforeOrder(int parenthesisCountBeforeOrder) {
326        this.parenthesisCountBeforeOrder = parenthesisCountBeforeOrder;
327    }
328
329    public void setAll(boolean all) {
330        this.all = all;
331    }
332
333    public void setSetOperatorType(ESetOperatorType setOperatorType) {
334        this.setOperatorType = setOperatorType;
335    }
336
337    public void setWindowClause(TWindowClause windowClause) {
338        setNewSubNode(this.windowClause,windowClause,getAnchorNode());
339        this.windowClause = windowClause;
340    }
341
342    public void setLockingClauses(TPTNodeList<TLockingClause> lockingClauses) {
343        this.lockingClauses = lockingClauses;
344    }
345
346    public void setSelectDistinct(TSelectDistinct selectDistinct) {
347        setNewSubNode(this.selectDistinct,selectDistinct,getAnchorNode());
348        this.selectDistinct = selectDistinct;
349    }
350
351    public void setExpandOnClause(TExpandOnClause expandOnClause) {
352        setNewSubNode(this.expandOnClause,expandOnClause,getAnchorNode());
353        this.expandOnClause = expandOnClause;
354    }
355
356
357    public void setSetOperator(int setOperator) {
358        this.setOperator = setOperator;
359    }
360
361    public void setLeftStmt(TSelectSqlStatement leftStmt) {
362        this.leftStmt = leftStmt;
363    }
364
365    public void setRightStmt(TSelectSqlStatement rightStmt) {
366        this.rightStmt = rightStmt;
367    }
368
369    public void setValueClause(TValueClause valueClause) {
370        setNewSubNode(this.valueClause,valueClause,getAnchorNode());
371        this.valueClause = valueClause;
372    }
373
374    public void setOracleHint(String oracleHint) {
375        this.oracleHint = oracleHint;
376    }
377
378    public void setHiveHintClause(THiveHintClause hiveHintClause) {
379        setNewSubNode(this.hiveHintClause,hiveHintClause,getAnchorNode());
380        this.hiveHintClause = hiveHintClause;
381    }
382
383
384    public void setTransformClause(THiveTransformClause transformClause) {
385        setNewSubNode(this.transformClause,transformClause,getAnchorNode());
386        this.transformClause = transformClause;
387    }
388
389    public void setDistributeBy(TDistributeBy distributeBy) {
390        setNewSubNode(this.distributeBy,distributeBy,getAnchorNode());
391        this.distributeBy = distributeBy;
392    }
393
394
395    public void setIntoClause(TIntoClause intoClause) {
396        setNewSubNode(this.intoClause,intoClause,getAnchorNode());
397        this.intoClause = intoClause;
398    }
399
400    public void setOrderbyClause(TOrderBy newOrderbyClause) {
401        setNewSubNode(this.orderbyClause,newOrderbyClause,getAnchorNode());
402        this.orderbyClause = newOrderbyClause;
403    }
404
405//    public void setOrderbyClause(TOrderBy newOrderbyClause, TParseTreeNode anchorNode) {
406//        if (newOrderbyClause == null){
407//            //remove
408//            this.orderbyClause.removeTokens();
409//            this.orderbyClause = null;
410//        }else{
411//            if (this.orderbyClause != null){
412//                this.orderbyClause.replaceWithNewNode(newOrderbyClause);
413//            }else{
414//                doAppendNewNode(newOrderbyClause,anchorNode,false);
415//            }
416//            this.orderbyClause = newOrderbyClause;
417//        }
418//    }
419
420    public void setQualifyClause(TQualifyClause qualifyClause) {
421        setNewSubNode(this.qualifyClause,qualifyClause,getAnchorNode());
422        this.qualifyClause = qualifyClause;
423    }
424
425    public void setSampleClause(TSampleClause sampleClause) {
426        setNewSubNode(this.sampleClause,sampleClause,getAnchorNode());
427        this.sampleClause = sampleClause;
428    }
429
430    public void setTeradataWithClause(TTeradataWithClause teradataWithClause) {
431        setNewSubNode(this.teradataWithClause,teradataWithClause,getAnchorNode());
432        this.teradataWithClause = teradataWithClause;
433    }
434
435    public void setForUpdateClause(TForUpdate forUpdateClause) {
436        setNewSubNode(this.forUpdateClause,forUpdateClause,getAnchorNode());
437        this.forUpdateClause = forUpdateClause;
438    }
439
440
441    public void setComputeClause(TComputeClause computeClause) {
442        this.computeClause = computeClause;
443    }
444
445    public void setGroupByClause(TGroupBy groupByClause) {
446        setNewSubNode(this.groupByClause,groupByClause,getAnchorNode());
447        this.groupByClause = groupByClause;
448    }
449
450
451    public void setHierarchicalClause(THierarchical hierarchicalClause) {
452        setNewSubNode(this.hierarchicalClause,hierarchicalClause,getAnchorNode());
453        this.hierarchicalClause = hierarchicalClause;
454    }
455
456
457    public void setLimitClause(TLimitClause limitClause) {
458        setNewSubNode(this.limitClause,limitClause,getAnchorNode());
459        this.limitClause = limitClause;
460    }
461
462    public void setOffsetClause(TOffsetClause offsetClause) {
463        setNewSubNode(this.offsetClause,offsetClause,getAnchorNode());
464        this.offsetClause = offsetClause;
465    }
466
467    public void setOptionClause(TOptionClause optionClause) {
468        setNewSubNode(this.optionClause,optionClause,getAnchorNode());
469        this.optionClause = optionClause;
470    }
471
472    public void setIsolationClause(TIsolationClause isolationClause) {
473        setNewSubNode(this.isolationClause,isolationClause,getAnchorNode());
474        this.isolationClause = isolationClause;
475    }
476
477//    public void setHiveClusterBy(THiveClusterBy hiveClusterBy) {
478//        setNewSubNode(this.hiveClusterBy,hiveClusterBy,getAnchorNode());
479//        this.hiveClusterBy = hiveClusterBy;
480//    }
481
482
483    public void setSortBy(TSortBy sortBy) {
484        setNewSubNode(this.sortBy,sortBy,getAnchorNode());
485        this.sortBy = sortBy;
486    }
487
488    public void setIntoTableClause(TIntoTableClause intoTableClause) {
489        setNewSubNode(this.intoTableClause,intoTableClause,getAnchorNode());
490        this.intoTableClause = intoTableClause;
491    }
492
493    public int getParenthesisCountBeforeOrder() {
494        return parenthesisCountBeforeOrder;
495    }
496
497    public int getParenthesisCount() {
498        return parenthesisCount;
499    }
500
501    private boolean queryOfCTE;
502
503    public void setQueryOfCTE(boolean queryOfCTE) {
504        this.queryOfCTE = queryOfCTE;
505    }
506
507    public boolean isQueryOfCTE() {
508        return queryOfCTE;
509    }
510
511    /**
512     * Offset clause.
513     * <br>
514     * <pre>OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY;</pre>
515     * @return {@link TOffsetClause offset clause}
516     */
517    public TOffsetClause getOffsetClause() {
518        return offsetClause;
519    }
520
521    /**
522     * Fetch first/next clause
523     * <br>
524     * <pre>OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY;</pre>
525     * @return {@link TFetchFirstClause fetch first/next clause}
526     */
527    public TFetchFirstClause getFetchFirstClause() {
528
529        return fetchFirstClause;
530    }
531
532    private TFetchFirstClause fetchFirstClause;
533    private TOffsetClause offsetClause;
534
535    private TOptionClause optionClause;
536
537    /**
538     *
539     * @return {@link  TOptionClause sql server option clause}
540     *
541     * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause
542     */
543    public TOptionClause getOptionClause() {
544        return optionClause;
545    }
546
547
548    /**
549     *
550     * @return {@link TIsolationClause isolation clause}
551     */
552    public TIsolationClause getIsolationClause() {
553        return isolationClause;
554    }
555
556    private TIsolationClause isolationClause;
557
558//     private THiveClusterBy hiveClusterBy;
559//
560//    /**
561//     *
562//     * @return {@link THiveClusterBy Hive cluster by clause}
563//     */
564//    public THiveClusterBy getHiveClusterBy() {
565//        return hiveClusterBy;
566//    }
567
568    private TSortBy sortBy;
569
570    /**
571     *
572     * @return {@link TSortBy Hive sort by clause}
573     */
574    public TSortBy getSortBy() {
575        return sortBy;
576    }
577
578    private TIntoTableClause intoTableClause;
579
580    /**
581     *
582     * @return {@link TIntoTableClause informix into table clause}
583     */
584    public TIntoTableClause getIntoTableClause() {
585        return intoTableClause;
586    }
587
588    public void setSelectToken(TSourceToken selectToken) {
589        this.selectToken = selectToken;
590    }
591
592    /**
593     *
594     * @return SELECT token of this query.
595     */
596    public TSourceToken getSelectToken() {
597        return selectToken;
598    }
599
600    private TSourceToken selectToken = null;
601    
602    public static final int SET_OPERATOR_NONE = 0;
603
604    public static final int setOperator_union = 1;
605    public static final int setOperator_unionall = 2;
606    public static final int SET_OPERATOR_UNIONDISTINCT = 9;
607
608    public static final int setOperator_intersect = 3;
609    public static final int setOperator_intersectall = 4;
610    public static final int SET_OPERATOR_INTERSECTDISTINCT = 10;
611
612    public static final int setOperator_minus = 5;
613    public static final int setOperator_minusall = 6;
614    public static final int SET_OPERATOR_MINUSDISTINCT = 11;
615
616    public static final int setOperator_except = 7;
617    public static final int setOperator_exceptall = 8;
618    public static final int SET_OPERATOR_EXCEPTDISTINCT = 11;
619
620    public boolean isAll() {
621        return all;
622    }
623
624    private boolean all = false;
625
626    public boolean isSetOpDistinct() {
627        return setOpDistinct;
628    }
629
630    private boolean setOpDistinct = false;
631    private ESetOperatorType setOperatorType = ESetOperatorType.none;
632
633    public ESetOperatorType getSetOperatorType() {
634        return setOperatorType;
635    }
636
637    private  TWindowClause  windowClause;
638
639    /**
640     *
641     * @return {@link TWindowClause window clause.}
642     */
643    public TWindowClause getWindowClause() {
644        return windowClause;
645    }
646
647    private TPTNodeList <TLockingClause> lockingClauses;
648
649    /**
650     *  PostgreSQL, for update of, for read only.
651     *  <br>
652     * @return list of {@link TLockingClause}
653     */
654    public TPTNodeList<TLockingClause> getLockingClauses() {
655        return lockingClauses;
656    }
657
658    /**
659     *
660     * @return {@link TSelectDistinct distinct clause}
661     */
662    public TSelectDistinct getSelectDistinct() {
663        return selectDistinct;
664    }
665
666    private TSelectDistinct selectDistinct = null;
667
668    /**
669     *
670     * @return {@link gudusoft.gsqlparser.nodes.TIntoClause into clause}
671     */
672    public TIntoClause getIntoClause() {
673        return intoClause;
674    }
675
676    private TIntoClause intoClause = null;
677
678
679    private TOrderBy orderbyClause;
680
681    /**
682     * @return {@link TOrderBy order by clause}
683     */
684    public TOrderBy getOrderbyClause() {
685        return orderbyClause;
686    }
687
688    public TSelectSqlStatement(EDbVendor dbvendor) {
689        super(dbvendor);
690        sqlstatementtype = ESqlStatementType.sstselect;
691    }
692
693    void buildsql() {
694    }
695
696    void clear() {
697    }
698
699    String getasprettytext() {
700        return "";
701    }
702
703    void iterate(TVisitorAbs pvisitor) {
704    }
705
706    /**
707     *
708     * @return {@link TQualifyClause teradata qualify clause}
709     */
710    public TQualifyClause getQualifyClause() {
711        return qualifyClause;
712    }
713
714    private TQualifyClause qualifyClause = null;
715    private TSampleClause sampleClause = null;
716    private TTeradataWithClause teradataWithClause = null;
717
718    /**
719     * @return {@link TTeradataWithClause Teradata with clause }
720     */
721    public TTeradataWithClause getTeradataWithClause() {
722        return teradataWithClause;
723    }
724
725    /**
726     *
727     * @return {@link gudusoft.gsqlparser.nodes.TSampleClause SQL Server sample clause}
728     */
729    public TSampleClause getSampleClause() {
730        return sampleClause;
731    }
732
733    /**
734     * @return {@link gudusoft.gsqlparser.nodes.TForUpdate for update clause}
735     */
736    public TForUpdate getForUpdateClause() {
737        return forUpdateClause;
738    }
739
740    private TForUpdate forUpdateClause;
741
742    /**
743     *
744     * @return {@link TComputeClause SQL Server compute clause}
745     */
746    public TComputeClause getComputeClause() {
747        return computeClause;
748    }
749
750    private TComputeClause computeClause = null;
751
752    /**
753     * @return  {@link TGroupBy group by clause and having clause}
754     */
755    public TGroupBy getGroupByClause() {
756        return groupByClause;
757    }
758
759    private TGroupBy groupByClause = null;
760
761
762    /**
763     * Oracle hierarchical_query_clause
764     * @return {@link gudusoft.gsqlparser.nodes.THierarchical Oracle hierarchical_query_clause}
765     */
766    public THierarchical getHierarchicalClause() {
767        return hierarchicalClause;
768    }
769
770    private THierarchical hierarchicalClause = null;
771
772    /**
773     * MySQL,PostgreSQL limit clause
774     * @return {@link TLimitClause MySQL,PostgreSQL limit clause}
775     */
776    public TLimitClause getLimitClause() {
777        return limitClause;
778    }
779
780    private TLimitClause limitClause = null;
781
782
783    private TExpandOnClause expandOnClause;
784
785    /**
786     *
787     * @return {@link TExpandOnClause Teradata expand on clause}
788     */
789    public TExpandOnClause getExpandOnClause() {
790        return expandOnClause;
791    }
792
793    /**
794     *
795     * The set operators UNION, EXCEPT, and INTERSECT correspond to the relational operators union, difference, and intersection.
796     * @return  set operator of this statement.If a set operator is not used, setOperator_none will be returned.
797     * otherwise, set operand can be fetched by using getLeftStmt() and getRightStmt().
798     *
799     * @deprecated As of v1.6.4.2, use {@link #getSetOperatorType()}  and {@link #isAll()} instead.
800     */
801    public int getSetOperator() {
802        return setOperator;
803    }
804
805    private int setOperator = 0;
806
807    /**
808     * Valid when {@link #getSetOperator} is not setOperator_none.
809     * @return left side query expression
810     */
811    public TSelectSqlStatement getLeftStmt() {
812        return leftStmt;
813    }
814
815    public TSelectSqlStatement getFarLeftStmt() {
816        TSelectSqlStatement current = leftStmt;
817        while (current.isCombinedQuery()) {
818            current = current.getLeftStmt();
819        }
820        return current;
821    }
822
823    /**
824     * Valid when {@link #getSetOperator} is not setOperator_none.
825     * @return right side query expression.
826     */
827    public TSelectSqlStatement getRightStmt() {
828        return rightStmt;
829    }
830
831    private TSelectSqlStatement leftStmt;
832    private TSelectSqlStatement rightStmt;
833
834    private TValueClause valueClause = null;
835
836    private String oracleHint;
837
838    private String hint;
839
840    private boolean isValueClause = false;
841
842    public boolean isValueClause() {
843        return isValueClause;
844    }
845
846    /**
847     * Hint for Oracle and MySQL
848     *
849     * @return hint string
850     */
851    public String getHint() {
852        return hint;
853    }
854
855    /**
856     * Hint for Oracle and MySQL
857     *
858     * @return  hint string.
859     */
860    /**
861     * @deprecated As of 2.0.4.5, replaced by {@link #getHint()}
862     */
863    public String getOracleHint() {
864        return oracleHint;
865    }
866
867    private THiveHintClause hiveHintClause;
868
869    /**
870     *
871     * @return {@link THiveHintClause Hive hint clause}
872     */
873    public THiveHintClause getHiveHintClause() {
874        return hiveHintClause;
875    }
876
877    private THiveTransformClause transformClause;
878
879    /**
880     *
881     * @return {@link THiveTransformClause Hive from clause}
882     */
883    public THiveTransformClause getTransformClause() {
884        return transformClause;
885    }
886
887    private TDistributeBy distributeBy;
888
889    /**
890     *
891     * @return {@link TDistributeBy Hive distribute by clause}
892     */
893    public TDistributeBy getDistributeBy() {
894        return distributeBy;
895    }
896
897    /**
898     * DB2 value clause
899     * @return {@link TValueClause DB2 value clause}
900     */
901    public TValueClause getValueClause() {
902        return valueClause;
903    }
904
905    public void setChildOfCombinedQuery(boolean childOfCombinedQuery) {
906        this.childOfCombinedQuery = childOfCombinedQuery;
907    }
908
909    public boolean isChildOfCombinedQuery() {
910
911        return childOfCombinedQuery;
912    }
913
914    private boolean childOfCombinedQuery = false;
915
916
917    @Override
918    public TreeMap<String,TResultColumn> getExpandedResultColumns() {
919        if (this.setOperatorType == ESetOperatorType.none){
920            return super.getExpandedResultColumns();
921        }else{
922            return this.getLeftStmt().getExpandedResultColumns();
923        }
924    }
925
926    private ArrayList<TSelectSqlStatement> flattenSelects = null;
927
928    public ArrayList<TSelectSqlStatement> getFlattenedSelects() {
929        if (!isCombinedQuery()) return null;
930        if (this.flattenSelects != null) return this.flattenSelects;
931
932        this.flattenSelects = new ArrayList<TSelectSqlStatement>();
933        this.flattenSelects.add(this.rightStmt);
934        doFlattenCombinedSelect(this.leftStmt,this.flattenSelects);
935
936        Collections.reverse(this.flattenSelects);
937        return flattenSelects;
938    }
939
940    void doFlattenCombinedSelect(TSelectSqlStatement select, ArrayList<TSelectSqlStatement> container){
941        TSelectSqlStatement current = select;
942        while (current.isCombinedQuery()){
943            container.add(current.getRightStmt());
944            current = current.getLeftStmt();
945        }
946        container.add(current);
947    }
948
949    /**
950     * This function is used internal. DON'T call it explicitly.
951     *
952     * @param psql input query.
953     * @return  zero means there is no syntax error detected.
954     */
955    public int doParseStatement(TCustomSqlStatement psql) {
956        if (rootNode == null) return -1;
957        TSelectSqlNode selectNode = (TSelectSqlNode)rootNode;
958
959        if (this.sourcetokenlist.size() == 0){
960            // subquery nested in other statements.
961            this.setStartToken(selectNode.getStartToken());
962            this.setEndToken(selectNode.getEndToken());
963        }
964
965        super.doParseStatement(psql);
966        this.selectToken = selectNode.getSelectToken();
967        parenthesisCount = selectNode.getParenthesisCount();
968        parenthesisCountBeforeOrder = selectNode.getParenthissisCountBeforeOrder();
969
970        setOperator = selectNode.getSetOperator();
971        initSetOperatorFields();
972
973        if(selectNode.isCombinedQuery()){
974            TCustomSqlStatement lcParentSql = psql;
975            if ((lcParentSql == null)||(!childOfCombinedQuery)){
976                lcParentSql = this;
977            }
978
979            if (selectNode.cteList != null){
980                this.setCteList(selectNode.cteList);
981                for(int i=0;i<getCteList().size();i++){
982                    getCteList().getCTE(i).doParse(this,ESqlClause.cte);
983                }
984            }
985
986            // Oracle 12c WITH FUNCTION/PROCEDURE support
987            if (selectNode.getWithPlsqlItems() != null){
988                this.setWithPlsqlItems(selectNode.getWithPlsqlItems());
989            }
990
991            // Iterative construction of the left-recursive UNION/INTERSECT/EXCEPT chain.
992            // This avoids StackOverflow for queries with many set operations (e.g., 2000+ UNION ALL).
993            // We collect the chain of combined query nodes, set up their properties top-down,
994            // then process leaf children and clauses from deepest to shallowest.
995
996            ArrayList<TSelectSqlStatement> stmtChain = new ArrayList<>();
997            ArrayList<TSelectSqlNode> nodeChain = new ArrayList<>();
998
999            stmtChain.add(this);
1000            nodeChain.add(selectNode);
1001
1002            TSelectSqlStatement currentStmt = this;
1003            TSelectSqlNode currentNode = selectNode;
1004
1005            // Walk down the left chain, creating intermediate TSelectSqlStatements
1006            while (currentNode.getLeftNode() != null && currentNode.getLeftNode().isCombinedQuery()) {
1007                TSelectSqlNode leftNode = currentNode.getLeftNode();
1008
1009                TSelectSqlStatement nextStmt = new TSelectSqlStatement(dbvendor);
1010                nextStmt.rootNode = leftNode;
1011                nextStmt.setChildOfCombinedQuery(true);
1012
1013                // Wire up parent's leftStmt
1014                currentStmt.leftStmt = nextStmt;
1015
1016                // Inline common setup (equivalent of super.doParseStatement + field init)
1017                if (nextStmt.sourcetokenlist.size() == 0) {
1018                    nextStmt.setStartToken(leftNode.getStartToken());
1019                    nextStmt.setEndToken(leftNode.getEndToken());
1020                }
1021                // Equivalent of TCustomSqlStatement.doParseStatement(lcParentSql)
1022                nextStmt.setParentStmt(lcParentSql);
1023                nextStmt.setFrameStack(lcParentSql.getFrameStack());
1024                lcParentSql.getStmtScope().incrementCurrentStmtIndex();
1025                nextStmt.setQueryId(String.format("%s#stmt_%d_%s",
1026                        lcParentSql.getQueryId(),
1027                        lcParentSql.getStmtScope().getCurrentStmtIndex(),
1028                        nextStmt.sqlstatementtype));
1029                nextStmt.setStmtScope(new TStmtScope(lcParentSql.getStmtScope(), nextStmt));
1030                if (nextStmt.getStartToken() == null && nextStmt.rootNode != null) {
1031                    nextStmt.setStartToken(nextStmt.rootNode.getStartToken());
1032                }
1033                if (nextStmt.getEndToken() == null && nextStmt.rootNode != null) {
1034                    nextStmt.setEndToken(nextStmt.rootNode.getEndToken());
1035                }
1036                if (nextStmt.getGsqlparser() == null && nextStmt.rootNode != null) {
1037                    nextStmt.setGsqlparser(nextStmt.rootNode.getGsqlparser());
1038                }
1039
1040                nextStmt.selectToken = leftNode.getSelectToken();
1041                nextStmt.parenthesisCount = leftNode.getParenthesisCount();
1042                nextStmt.parenthesisCountBeforeOrder = leftNode.getParenthissisCountBeforeOrder();
1043                nextStmt.setOperator = leftNode.getSetOperator();
1044                nextStmt.initSetOperatorFields();
1045
1046                stmtChain.add(nextStmt);
1047                nodeChain.add(leftNode);
1048
1049                currentStmt = nextStmt;
1050                currentNode = leftNode;
1051            }
1052
1053            // Create and process the leftmost leaf (non-combined SELECT)
1054            TSelectSqlStatement leftmostLeaf = new TSelectSqlStatement(dbvendor);
1055            leftmostLeaf.rootNode = currentNode.getLeftNode();
1056            leftmostLeaf.setChildOfCombinedQuery(true);
1057            currentStmt.leftStmt = leftmostLeaf;
1058            leftmostLeaf.doParseStatement(lcParentSql);
1059
1060            // Process right children and clauses from deepest to shallowest
1061            for (int i = stmtChain.size() - 1; i >= 0; i--) {
1062                TSelectSqlStatement stmt = stmtChain.get(i);
1063                TSelectSqlNode node = nodeChain.get(i);
1064
1065                // Create and process right child (always a leaf for left-recursive grammar)
1066                stmt.rightStmt = new TSelectSqlStatement(dbvendor);
1067                stmt.rightStmt.rootNode = node.getRightNode();
1068                stmt.rightStmt.setChildOfCombinedQuery(true);
1069                stmt.rightStmt.doParseStatement(lcParentSql);
1070
1071                // Handle clauses for this level
1072                if (node.getOrderbyClause() != null) {
1073                    node.getOrderbyClause().doParse(stmt, ESqlClause.orderby);
1074                    stmt.orderbyClause = node.getOrderbyClause();
1075                }
1076                stmt.limitClause = node.getLimitClause();
1077                if (node.getForupdateClause() != null) {
1078                    node.getForupdateClause().doParse(stmt, ESqlClause.forUpdate);
1079                    stmt.forUpdateClause = node.getForupdateClause();
1080                }
1081                if (node.getComputeClause() != null) {
1082                    node.getComputeClause().doParse(stmt, ESqlClause.compute);
1083                    stmt.computeClause = node.getComputeClause();
1084                }
1085                stmt.optionClause = node.getOptionClause();
1086                stmt.timeTravel = node.getTimeTravel();
1087                stmt.hintClause = node.getHintClause();
1088            }
1089
1090            return 0;
1091        }
1092
1093        if (selectNode.getValueClause() != null){
1094            this.valueClause = selectNode.getValueClause();
1095            this.valueClause.doParse(this,ESqlClause.selectValue);
1096            isValueClause = true;
1097            return 0;
1098        }
1099
1100        if (selectNode.getTransformClause() != null){
1101            this.transformClause = selectNode.getTransformClause();
1102            this.transformClause.doParse(this,ESqlClause.transformClause);
1103        }
1104
1105        if (selectNode.cteList != null){
1106            this.setCteList(selectNode.cteList);
1107            this.getCteList().doParse(this,ESqlClause.cte);
1108        }
1109
1110        // Oracle 12c WITH FUNCTION/PROCEDURE support
1111        if (selectNode.getWithPlsqlItems() != null){
1112            this.setWithPlsqlItems(selectNode.getWithPlsqlItems());
1113        }
1114
1115        if (selectNode.isHiveFromQuery()){
1116            if(selectNode.getSelectSqlNodes() != null){
1117                for(int i=1;i<selectNode.getSelectSqlNodes().size();i++){
1118                    //start from the second, the first select statement is represented by this class instance.
1119
1120                    TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive);
1121                    select.rootNode = selectNode.getSelectSqlNodes().get(i);
1122                    select.doParseStatement(this);
1123                    this.getMultiSelectStatements().add(select);
1124                }
1125            }
1126
1127            // Hive: from query insert...
1128//            if (selectNode.getFromTableList() != null){
1129//                TFromTable lcFromTable;
1130//                TJoin lcJoin;
1131//
1132//                for(int i=0; i<selectNode.getFromTableList().size();i++){
1133//                    lcFromTable = selectNode.getFromTableList().getFromTable(i);
1134//                    TTable lcTable = null;
1135//
1136//                    if (lcFromTable.getFromtableType() != ETableSource.join){
1137//                        lcJoin = new TJoin();
1138//                        lcTable = analyzeFromTable(lcFromTable,true);
1139//                        lcTable.setEffectType(ETableEffectType.tetSelect);
1140//                        lcJoin.setTable(lcTable);
1141//                        lcJoin.setStartToken(lcJoin.getTable().getStartToken());
1142//                        lcJoin.setEndToken(lcJoin.getTable().getEndToken());
1143//                        lcJoin.setGsqlparser(getGsqlparser());
1144//                    }else{
1145//                        lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
1146//                        lcJoin.doParse(this, ESqlClause.join);
1147//
1148//                        if (lcFromTable.getLateralViewList() != null){
1149//                            for(TLateralView lateralView:lcFromTable.getLateralViewList()){
1150//                                addToTables(lateralView.createATable(this));
1151//                            }
1152//                        }
1153//                    }
1154//
1155//                    joins.addJoin(lcJoin);
1156//                }
1157//            }
1158
1159
1160//            if (selectNode.getHiveBodyList() != null){
1161//                for(int i = 0; i<selectNode.getHiveBodyList().size();i++){
1162//                    TParseTreeNode node1 = selectNode.getHiveBodyList().get(i);
1163//                    switch (node1.getNodeType()){
1164//                        case TStatementSqlNode.select:
1165//                            TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive);
1166//                            select.rootNode = node1;
1167//                            select.doParseStatement(this);
1168//                            this.getHiveBodyList().add(select);
1169//
1170//                            break;
1171//                        case TStatementSqlNode.insert:
1172//
1173//                            TInsertSqlStatement insert = new TInsertSqlStatement(EDbVendor.dbvhive);
1174//                            insert.rootNode = node1;
1175//                            insert.doParseStatement(this);
1176//                            this.getHiveBodyList().add(insert);
1177//                            break;
1178//                        default:
1179//                            break;
1180//                    }
1181//                }
1182//            }
1183           // return 0;
1184        }
1185
1186        // get oracle hint
1187        if((dbvendor == EDbVendor.dbvoracle)||(dbvendor == EDbVendor.dbvmysql)){
1188            TSourceToken lcnextst = this.selectToken.container.nextsolidtoken(this.selectToken.posinlist,1,true);
1189            while (lcnextst != null){
1190                if (!((lcnextst.tokentype == ETokenType.ttsimplecomment) || (lcnextst.tokentype == ETokenType.ttbracketedcomment))) break;
1191
1192                if (lcnextst.tokentype == ETokenType.ttbracketedcomment){
1193                    if (lcnextst.toString().startsWith("/*+")){
1194                       //lcnextst.setDbObjType(TObjectName.ttObjOracleHint);
1195                       lcnextst.setDbObjectType(EDbObjectType.oracleHint);
1196                       if (oracleHint == null){
1197                           oracleHint = lcnextst.toString();
1198                       }else {
1199                           oracleHint = oracleHint + " " + lcnextst.toString();
1200                       }
1201                    }
1202                }
1203
1204                if (lcnextst.tokentype == ETokenType.ttsimplecomment){
1205                    if (lcnextst.toString().startsWith("--+")){
1206                       //lcnextst.setDbObjType(TObjectName.ttObjOracleHint);
1207                        lcnextst.setDbObjectType(EDbObjectType.oracleHint);
1208                       if (oracleHint == null){
1209                           oracleHint = lcnextst.toString();
1210                       }else {
1211                           oracleHint = oracleHint + " " + lcnextst.toString();
1212                       }
1213                    }
1214                }
1215
1216                lcnextst = lcnextst.container.nextsolidtoken(lcnextst,1,true);
1217            }
1218
1219            hint = oracleHint;
1220        }
1221
1222        if (selectNode.getHiveHintClause() != null){
1223            hiveHintClause = selectNode.getHiveHintClause();
1224        }
1225
1226        isConsume = selectNode.isConsume();
1227
1228        if (selectNode.getTopClause() != null){
1229           selectNode.getTopClause().doParse(this,ESqlClause.top);
1230            this.setTopClause(selectNode.getTopClause()); 
1231        }
1232
1233 //       this.skipOffset = selectNode.getSkipOffset();
1234//        this.firstMax = selectNode.getFirstMax();
1235//        this.limitMax = selectNode.getLimitMax();
1236
1237        if (selectNode.getSelectDistinct() != null){
1238            this.selectDistinct = selectNode.getSelectDistinct();
1239        }
1240
1241        this.selectModifiers = selectNode.getSelectModifiers();
1242
1243        TFromTable lcFromTable = null;
1244        TJoin lcJoin = null;
1245
1246        if (selectNode.getFromTableList() != null){
1247            fromClause = new TFromClause(this.getRelations());
1248            fromClause.setStartToken(selectNode.getFromTableList().getStartToken());
1249            fromClause.setEndToken(selectNode.getFromTableList().getEndToken());
1250
1251            for(int i=0; i<selectNode.getFromTableList().size();i++){
1252                 lcFromTable = selectNode.getFromTableList().getFromTable(i);
1253                 lcJoin = analyzeTableOrJoin(lcFromTable);
1254                 joins.addJoin(lcJoin);
1255            }
1256        }
1257
1258        if (selectNode.getResultColumnList() != null){
1259            this.setResultColumnList(selectNode.getResultColumnList());
1260
1261//            if ((this.getResultColumnList().size() > 10)
1262//                    &&(this.getTables().size() == 1)
1263//                    &&(this.getTables().getTable(0).getTableType() == ETableSource.subquery)
1264//                    &&( this.getTables().getTable(0).getSubquery().getResultColumnList().size() == this.getResultColumnList().size() )
1265//            ){
1266//                TTable t0 = this.getTables().getTable(0);
1267//                ArrayList<TResultColumn> targetColumnArrayList = this.getResultColumnList().getSortedColumns();
1268//                ArrayList<TResultColumn> sourceColumnArrayList = t0.getSubquery().getResultColumnList().getSortedColumns();
1269//                int i=0;
1270//                for(TResultColumn rc:targetColumnArrayList){
1271//                    TObjectName targetColumn = rc.getExpr().getObjectOperand();
1272//                    TResultColumn sourceResultColumn = sourceColumnArrayList.get(i++);
1273//                    //TObjectName sourceColumn = sourceResultColumn.getExpr().getObjectOperand();
1274//                    if (targetColumn != null){
1275//                        //System.out.println(targetColumn+"\t->\t"+sourceResultColumn.getDisplayName());
1276//                        targetColumn.setSourceTable(t0);
1277//                        t0.getLinkedColumns().addObjectName(targetColumn);
1278//                        targetColumn.setSourceColumn(sourceResultColumn);
1279//                        sourceResultColumn.getTargetColumns().addObjectName(targetColumn);
1280//                    }
1281//                }
1282//            }
1283
1284            selectNode.getResultColumnList().doParse(this,ESqlClause.selectList);
1285
1286            // Slice 73: link DISTINCT ON expression list (PostgreSQL /
1287            // Greenplum `SELECT DISTINCT ON (cols) ...`) so each
1288            // TObjectName inside gets dbObjectType=column and
1289            // sourceTable populated. Without this, the expressions
1290            // remain EDbObjectType.unknown. The legacy column-linker
1291            // (linkColumnToTable) is invoked here via TExpression.doParse;
1292            // resolver-2 picks the same expressions up via the
1293            // TSelectDistinct.acceptChildren descent that slice 73
1294            // also wires up. Tables are populated by the FROM clause
1295            // loop above so column linking has a relation list to
1296            // resolve against. Mirrors the TGroupBy.doParse →
1297            // items.doParse pattern.
1298            if (this.selectDistinct != null
1299                    && this.selectDistinct.getExpressionList() != null) {
1300                TExpressionList distinctOnExprList =
1301                        this.selectDistinct.getExpressionList();
1302                for (int i = 0; i < distinctOnExprList.size(); i++) {
1303                    TExpression e = distinctOnExprList.getExpression(i);
1304                    if (e != null) {
1305                        e.doParse(this, ESqlClause.unknown);
1306                    }
1307                }
1308            }
1309
1310            for(int i=0;i<selectNode.getResultColumnList().size();i++){
1311                TResultColumn resultColumn = selectNode.getResultColumnList().getResultColumn(i);
1312                if (resultColumn.getExpr().toString().endsWith("*")){
1313                    //System.out.println(resultColumn.toString()+":"+resultColumn.getStartToken().lineNo+","+resultColumn.getStartToken().columnNo);
1314                    if (resultColumn.getExpr().toString().startsWith("*")){
1315                        // add all result columns in from tables
1316                        for(int j=0;j<getTables().size();j++){
1317                            if (getTables().getTable(j).getTableType() == ETableSource.subquery){
1318                                getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns());
1319                            }else{
1320                                // ToDo for real table
1321                            }
1322                            //System.out.println("\t"+getTables().getTable(j).toString()+",\t"+getTables().getTable(j).getTableType()+",\t"+getTables().getTable(j).isCTEName());
1323                        }
1324                        if (getTables().size() == 1){
1325                            resultColumn.getExpr().getObjectOperand().setSourceTable(getTables().getTable(0));
1326                        }
1327
1328                    }else{
1329                        for(int j=0;j<getTables().size();j++){
1330                            if (getTables().getTable(j).getAliasName().equalsIgnoreCase( resultColumn.toString().split("[.]")[0])){
1331                                if (getTables().getTable(j).getTableType() == ETableSource.subquery){
1332                                    getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns());
1333                                }else{
1334                                    // ToDo for real table
1335                                }
1336                                resultColumn.getExpr().getObjectOperand().setSourceTable(getTables().getTable(j));
1337                                break;
1338                            }
1339                        }
1340                    }
1341                }else{
1342                    getExpandedResultColumns().put(IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,resultColumn.getDisplayName()),resultColumn);
1343                }
1344            }
1345        }
1346
1347        if (selectNode.getIntoClause() != null){
1348            this.intoClause = selectNode.getIntoClause();
1349            this.intoClause.doParse(this,ESqlClause.selectInto);
1350        }
1351
1352
1353        if (selectNode.getWhereCondition() != null){
1354            selectNode.getWhereCondition().doParse(this,ESqlClause.where);
1355            this.setWhereClause( selectNode.getWhereCondition());
1356        }
1357
1358        if (selectNode.getHierarchicalClause() != null){
1359         selectNode.getHierarchicalClause().doParse(this,ESqlClause.hierarchical);
1360         this.hierarchicalClause = selectNode.getHierarchicalClause();
1361        }
1362
1363        if (selectNode.getGroupByClause() != null){
1364            selectNode.getGroupByClause().doParse(this,ESqlClause.groupby);
1365            this.groupByClause = selectNode.getGroupByClause(); 
1366        }
1367
1368        if (selectNode.getQualifyClause() != null){
1369            selectNode.getQualifyClause().doParse(this,ESqlClause.qualify);
1370            this.qualifyClause = selectNode.getQualifyClause(); 
1371        }
1372
1373        if (selectNode.getSampleClause() != null){
1374            selectNode.getSampleClause().doParse(this,ESqlClause.sample);
1375            this.sampleClause = selectNode.getSampleClause();
1376        }
1377
1378        if (selectNode.getExpandOnClause() != null){
1379            selectNode.getExpandOnClause().doParse(this,ESqlClause.expandOn);
1380            this.expandOnClause = selectNode.getExpandOnClause();
1381        }
1382
1383        if (selectNode.getWithClause() != null){
1384            selectNode.getWithClause().doParse(this,ESqlClause.teradataWith);
1385            this.teradataWithClause  = selectNode.getWithClause();
1386        }
1387
1388        if (selectNode.getOrderbyClause() != null){
1389            selectNode.getOrderbyClause().doParse(this,ESqlClause.orderby);
1390            this.orderbyClause = selectNode.getOrderbyClause(); 
1391        }
1392
1393        if (selectNode.getLockingClauses() != null){
1394           selectNode.getLockingClauses().doParse(this,ESqlClause.lockingClause);
1395            this.lockingClauses = selectNode.getLockingClauses();
1396        }
1397
1398        this.sortBy = selectNode.getSortBy();
1399        if (this.sortBy != null){
1400            this.sortBy.doParse(this,ESqlClause.sortby);
1401        }
1402
1403        this.clusterBy = selectNode.getClusterBy();
1404        if (this.clusterBy != null){
1405            this.clusterBy.doParse(this,ESqlClause.cluster);
1406        }
1407
1408        this.windowClause = selectNode.getWindowClause();
1409        if (this.windowClause != null){
1410            this.windowClause.doParse(this,ESqlClause.windowClause);
1411        }
1412        this.limitClause = selectNode.getLimitClause();
1413        if (this.limitClause != null){
1414            this.limitClause.doParse(this,ESqlClause.limit);
1415        }
1416
1417       if (selectNode.getForupdateClause() != null){
1418            selectNode.getForupdateClause().doParse(this,ESqlClause.forUpdate);
1419            this.forUpdateClause  = selectNode.getForupdateClause();
1420        }
1421
1422        if (selectNode.getComputeClause() != null){
1423            selectNode.getComputeClause().doParse(this,ESqlClause.compute);
1424            this.computeClause = selectNode.getComputeClause(); 
1425        }
1426
1427        this.intoTableClause = selectNode.getIntoTableClause();
1428
1429        if (selectNode.getDistributeBy() != null){
1430            this.distributeBy = selectNode.getDistributeBy();
1431            this.distributeBy.doParse(this,ESqlClause.distributeBy);
1432        }
1433
1434
1435        this.isolationClause = selectNode.getIsolationClause();
1436
1437        this.optionClause = selectNode.getOptionClause();
1438
1439        this.offsetClause = selectNode.getOffsetClause();
1440        this.fetchFirstClause = selectNode.getFetchFirstClause();
1441
1442        this.timeTravel = selectNode.getTimeTravel();
1443        this.hintClause = selectNode.getHintClause();
1444
1445        if (selectNode.getForXMLClause() != null){
1446            if (tables.size() > 0){
1447                tables.getTable(0).setForXMLClause(selectNode.getForXMLClause());
1448            }
1449        }
1450
1451        // StarRocks pipe operator support
1452        this.pipeOperators = selectNode.getPipeOperators();
1453        this.isPipeQuery = selectNode.isPipeQuery();
1454
1455        return 0;
1456    }
1457
1458    /**
1459     * Determine whether The UNION, EXCEPT and INTERSECT operators were used.
1460     * @return true if one of those operators were used.
1461     */
1462    public boolean isCombinedQuery(){
1463    // combine multiple queries using the set operators UNION, UNION ALL, INTERSECT, and MINUS.
1464        return (setOperator > 0);
1465    }
1466
1467    /**
1468     * Initialize setOperatorType, all, and setOpDistinct fields from setOperator value.
1469     * Used by doParseStatement's iterative combined query construction.
1470     */
1471    private void initSetOperatorFields() {
1472        switch (setOperator) {
1473            case SET_OPERATOR_NONE:
1474                setOperatorType = ESetOperatorType.none; all = false; break;
1475            case setOperator_union:
1476                setOperatorType = ESetOperatorType.union; all = false; break;
1477            case setOperator_unionall:
1478                setOperatorType = ESetOperatorType.union; all = true; break;
1479            case SET_OPERATOR_UNIONDISTINCT:
1480                setOperatorType = ESetOperatorType.union; setOpDistinct = true; break;
1481            case setOperator_intersect:
1482                setOperatorType = ESetOperatorType.intersect; all = false; break;
1483            case setOperator_intersectall:
1484                setOperatorType = ESetOperatorType.intersect; all = true; break;
1485            case setOperator_except:
1486                setOperatorType = ESetOperatorType.except; all = false; break;
1487            case setOperator_exceptall:
1488                setOperatorType = ESetOperatorType.except; all = true; break;
1489            case setOperator_minus:
1490                setOperatorType = ESetOperatorType.minus; all = false; break;
1491            case setOperator_minusall:
1492                setOperatorType = ESetOperatorType.minus; all = true; break;
1493            case SET_OPERATOR_INTERSECTDISTINCT:
1494                setOperatorType = ESetOperatorType.intersect; setOpDistinct = true; break;
1495            case SET_OPERATOR_EXCEPTDISTINCT:
1496                setOperatorType = ESetOperatorType.except; setOpDistinct = true; break;
1497        }
1498    }
1499
1500    public void accept(TParseTreeVisitor v)
1501    {
1502        v.preVisit(this);
1503        v.postVisit(this);
1504    }
1505
1506    /**
1507     * Accept visitor to visit this class.
1508     * @param v user defined visitor.
1509     */
1510    public void acceptChildren(TParseTreeVisitor v)
1511    {
1512
1513        if(this.isCombinedQuery()){
1514
1515            // Iterative traversal for combined queries to avoid StackOverflow
1516            // on deeply nested left-recursive UNION/INTERSECT/EXCEPT chains.
1517            // Collect the left-recursive chain of combined query nodes.
1518            ArrayList<TSelectSqlStatement> chain = new ArrayList<>();
1519            TSelectSqlStatement current = this;
1520            while (current.isCombinedQuery()) {
1521                chain.add(current);
1522                current = current.getLeftStmt();
1523            }
1524            // 'current' is now the leftmost leaf (non-combined SELECT)
1525
1526            // Phase 1: preVisit all combined nodes and their CTEs, from root to deepest
1527            for (int i = 0; i < chain.size(); i++) {
1528                TSelectSqlStatement node = chain.get(i);
1529                v.preVisit(node);
1530                if (node.getCteList() != null) {
1531                    node.getCteList().acceptChildren(v);
1532                }
1533            }
1534
1535            // Phase 2: Visit leftmost leaf SELECT
1536            current.acceptChildren(v);
1537
1538            // Phase 3: Visit right branches and postVisit, from deepest to root
1539            for (int i = chain.size() - 1; i >= 0; i--) {
1540                TSelectSqlStatement node = chain.get(i);
1541                node.getRightStmt().acceptChildren(v);
1542
1543                if (node.getOrderbyClause() != null) {
1544                    node.getOrderbyClause().acceptChildren(v);
1545                }
1546                if (node.getLimitClause() != null) {
1547                    node.getLimitClause().acceptChildren(v);
1548                }
1549                if (node.getForUpdateClause() != null) {
1550                    node.getForUpdateClause().acceptChildren(v);
1551                }
1552                if (node.getComputeClause() != null) {
1553                    node.getComputeClause().acceptChildren(v);
1554                }
1555                v.postVisit(node);
1556            }
1557
1558            return ;
1559        }
1560
1561        // System.out.println(this.toString().hashCode()+" "+ this.toString().substring(0,50));
1562
1563        v.preVisit(this);
1564
1565        if (this.getTransformClause() != null){
1566            this.getTransformClause().acceptChildren(v);
1567        }
1568
1569        if (this.getCteList() != null){
1570            this.getCteList().acceptChildren(v);
1571        }
1572
1573        if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){
1574//            fromClause.acceptChildren(v);
1575            v.preVisit(fromClause);
1576            for(TTable table:getRelations()){
1577                table.acceptChildren(v);
1578            }
1579            v.postVisit(fromClause);
1580        }else{
1581            if (this.getJoins() != null){
1582                this.getJoins().acceptChildren(v);
1583            }
1584        }
1585
1586        if (this.getHiveHintClause() != null){
1587            this.getHiveHintClause().acceptChildren(v);
1588        }
1589
1590
1591        if (this.getTopClause() != null){
1592            this.getTopClause().acceptChildren(v);
1593        }
1594
1595        if (this.getSelectDistinct() != null){
1596            this.getSelectDistinct().acceptChildren(v);
1597        }
1598        
1599        if (this.getResultColumnList() != null){
1600            this.getResultColumnList().acceptChildren(v);
1601        }
1602
1603        if (this.getIntoClause() != null){
1604            this.getIntoClause().acceptChildren(v);
1605        }
1606
1607
1608        if (this.getWhereClause() != null){
1609            this.getWhereClause().acceptChildren(v);
1610        }
1611
1612        if (this.getHierarchicalClause() != null){
1613            this.getHierarchicalClause().acceptChildren(v);
1614        }
1615
1616        if (this.getGroupByClause() != null){
1617            this.getGroupByClause().acceptChildren(v);
1618        }
1619
1620        if (this.getQualifyClause() != null){
1621            this.getQualifyClause().acceptChildren(v);
1622        }
1623
1624        if (this.getSampleClause() != null){
1625            this.getSampleClause().acceptChildren(v);
1626        }
1627
1628        if (this.getExpandOnClause() != null){
1629            this.getExpandOnClause().acceptChildren(v);
1630        }
1631
1632        if (this.getTeradataWithClause() != null){
1633            this.getTeradataWithClause().acceptChildren(v);
1634        }
1635
1636        if (this.getOrderbyClause() != null){
1637            this.getOrderbyClause().acceptChildren(v);
1638        }
1639
1640        if (this.getLockingClauses() != null){
1641            this.getLockingClauses().acceptChildren(v);
1642        }
1643
1644        if (this.getSortBy() != null){
1645            this.getSortBy().acceptChildren(v);
1646        }
1647
1648        if (this.getClusterBy() != null){
1649            this.getClusterBy().acceptChildren(v);
1650        }
1651
1652        if (this.getWindowClause() != null){
1653            this.getWindowClause().acceptChildren(v);
1654        }
1655
1656        if (this.getLimitClause() != null){
1657            this.getLimitClause().acceptChildren(v);
1658        }
1659
1660        if (this.getForUpdateClause() != null){
1661            this.getForUpdateClause().acceptChildren(v);
1662        }
1663
1664        if (this.getComputeClause() != null){
1665            this.getComputeClause().acceptChildren(v);
1666        }
1667
1668        if (this.getIntoTableClause() != null){
1669            this.getIntoTableClause().acceptChildren(v);
1670        }
1671
1672        if (this.getDistributeBy() != null){
1673            this.getDistributeBy().acceptChildren(v);
1674        }
1675
1676        if (this.getIsolationClause() != null){
1677            this.getIsolationClause().acceptChildren(v);
1678        }
1679
1680        if (this.getOptionClause() != null){
1681            this.getOptionClause().acceptChildren(v);
1682        }
1683
1684        if (this.getOffsetClause() != null){
1685            this.getOffsetClause().acceptChildren(v);
1686        }
1687
1688        if (this.getFetchFirstClause() != null){
1689            this.getFetchFirstClause().acceptChildren(v);
1690        }
1691
1692        if (this.getTimeTravel() != null){
1693            this.getTimeTravel().acceptChildren(v);
1694        }
1695
1696        if (this.getHintClause() != null){
1697            this.getHintClause().acceptChildren(v);
1698        }
1699
1700        v.postVisit(this);
1701        return ;
1702
1703    };
1704
1705    /**
1706     *  Add an order by clause to this class.
1707     * @param orderByStr new order by string
1708     * @return added order by clause.
1709     */
1710    public  TOrderBy addOrderBy(String orderByStr){
1711        if (this.getOrderbyClause() != null){
1712            this.getOrderbyClause().addOrderByItem(orderByStr);
1713        }else{
1714
1715            TOrderBy orderBy = new TOrderBy();
1716            orderBy.setGsqlparser(this.getGsqlparser());
1717            orderBy.setString(" order by "+orderByStr);
1718            this.orderbyClause = orderBy;
1719            TSourceToken last_token = null;
1720            if (this.getGroupByClause() != null){
1721                last_token = this.getGroupByClause().getEndToken();
1722            }else if (this.getWhereClause() != null){
1723                last_token = this.getWhereClause().getEndToken();
1724            }else{
1725                last_token = joins.getEndToken();
1726            }
1727
1728            orderbyClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1);
1729
1730           for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){
1731               TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i);
1732               if (node instanceof TSelectSqlStatement)
1733               {
1734                   // change all end token of parse tree node except the last order by item
1735                   node.setEndToken(orderbyClause.getEndToken());
1736               }
1737           }
1738        }
1739
1740        return this.getOrderbyClause();
1741    }
1742
1743    /**
1744     *  this function is alias of addWhereClause
1745     * @param condition new condition
1746     * @return new where clause
1747     */
1748    public TWhereClause addCondition(String condition){
1749        return  addWhereClause(condition);
1750    }
1751
1752    public TWhereClause addConditionOR(String condition){
1753        return  addWhereClauseOR(condition);
1754    }
1755
1756    public  TWhereClause addWhereClause(String condition){
1757       return doAddWhereClause(condition,true);
1758    }
1759
1760    public  TWhereClause addWhereClauseOR(String condition){
1761       return doAddWhereClause(condition,false);
1762    }
1763
1764    protected  TWhereClause doAddWhereClause(String condition, boolean isAnd){
1765
1766        if (this.getWhereClause() != null){
1767                if (isAnd){
1768                    this.getWhereClause().getCondition().addANDCondition(condition);
1769                }else{
1770                    this.getWhereClause().getCondition().addORCondition(condition);
1771                }
1772
1773          }else{
1774             TWhereClause whereClause = new TWhereClause();
1775             whereClause.setGsqlparser(this.getGsqlparser());
1776             whereClause.setString(" where "+condition);
1777             this.setWhereClause(whereClause);
1778
1779            TSourceToken last_token = null;
1780            TJoin lastjoin = joins.getJoin(joins.size()-1);
1781            if (lastjoin.getJoinItems().size() > 0){
1782                TJoinItem lastitem = lastjoin.getJoinItems().getJoinItem(lastjoin.getJoinItems().size()-1);
1783                 last_token = lastitem.getEndToken();
1784            }else {
1785                last_token = joins.getEndToken();
1786            }
1787
1788             whereClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1);
1789
1790            for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){
1791                TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i);
1792                if (!((node instanceof TJoinList)
1793                        ||(node instanceof TJoin)
1794                        ||(node instanceof TJoinItemList)
1795                        ||(node instanceof TJoinItem)
1796                        ))
1797                {
1798                    // change all end token of parse tree node except the last order by item
1799                    node.setEndToken(whereClause.getEndToken());
1800                }
1801            }
1802
1803          }
1804           return this.getWhereClause();
1805    }
1806
1807    private ArrayList<String> columnsInFromClause = null;
1808
1809
1810    @Override
1811    public TFromClause getFromClause() {
1812        // #todo , select union 类型的 sql 语句,需要穿透到低层的各个 子 select 语句,需要进一步完善
1813        TFromClause ret = super.getFromClause();
1814        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1815            return   this.getRightStmt().getFromClause();
1816        }else{
1817            return  ret;
1818        }
1819    }
1820
1821    public TResultColumnList getResultColumnList(boolean useColumnsFromLeftmost) {
1822        TResultColumnList ret = super.getResultColumnList();
1823        if (ret != null) return ret;
1824
1825        if (isCombinedQuery()){
1826            if (useColumnsFromLeftmost) {
1827                return this.getFarLeftStmt().getResultColumnList();
1828            } else {
1829                return   this.getRightStmt().getResultColumnList();
1830            }
1831        }
1832        return ret;
1833
1834
1835//        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1836//            return   this.getRightStmt().getResultColumnList();
1837//        }else{
1838//            return  ret;
1839//        }
1840    }
1841
1842    @Override
1843    public TResultColumnList getResultColumnList() {
1844        return getResultColumnList(false);
1845
1846//        TResultColumnList ret = super.getResultColumnList();
1847//        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1848//            return   this.getRightStmt().getResultColumnList();
1849//        }else{
1850//            return  ret;
1851//        }
1852    }
1853
1854    public ArrayList<String> getColumnsInFromClause() {
1855        if (columnsInFromClause != null) return columnsInFromClause;
1856        columnsInFromClause = new ArrayList<String>();
1857        TTable lcTable;
1858        for(int j=0;j<tables.size();j++){
1859            lcTable = tables.getTable(j);
1860            switch (lcTable.getTableType()){
1861                case objectname:
1862                    break;
1863                case subquery:
1864                    TSelectSqlStatement subQuery = lcTable.getSubquery();
1865                                        if (subQuery.getResultColumnList() != null)
1866                                                for(int i=0;i<subQuery.getResultColumnList().size();i++){
1867                                                        TResultColumn resultColumn = subQuery.getResultColumnList().getResultColumn(i);
1868                                                        String aliasName = null;
1869                                                        if (resultColumn.getAliasClause() != null){
1870                                                                aliasName = resultColumn.getAliasClause().getAliasName().toString();
1871                                                        }else{
1872                                                                if (resultColumn.getExpr().getObjectOperand() != null){
1873                                                                        aliasName = resultColumn.getExpr().getObjectOperand().toString();
1874                                                                }
1875                                                        }
1876                                                        if (aliasName != null){
1877                                                                columnsInFromClause.add(TSQLEnv.getObjectName(aliasName));
1878                                                        }
1879                                                }
1880                    break;
1881            }
1882        }
1883        return columnsInFromClause;
1884    }
1885
1886    public void addColumnInSelectListToSQLEnv(TSQLTable sqlTable){
1887
1888        if (this.getValueClause() != null) return;
1889                
1890                if (this.getResultColumnList() != null)
1891                        for(int i=0;i<this.getResultColumnList().size();i++){
1892                                TResultColumn resultColumn = this.getResultColumnList().getResultColumn(i);
1893                                String aliasName = null;
1894                                if (resultColumn.getAliasClause() != null){
1895                                        aliasName = resultColumn.getAliasClause().getAliasName().toString();
1896                                }else{
1897                                        if (resultColumn.getExpr().getObjectOperand() != null){
1898                                                aliasName = resultColumn.getExpr().getObjectOperand().toString();
1899                                        }
1900                                }
1901                                if (aliasName != null){
1902                                        sqlTable.addColumn(TSQLEnv.getObjectName(aliasName));
1903                                }
1904                        }
1905    }
1906
1907    /**
1908     * search column in the select list
1909     *
1910     * Internal function, DON'T call it explicitly.
1911     * @param pColumn
1912     * @param pMustIn
1913     * @return true if found.
1914     */
1915    public boolean searchColumnInResultSet(TObjectName pColumn,boolean pMustIn){
1916        boolean lcResult = false;
1917        int candidateTableCnt = 0;
1918        int numOfColumnStar = 0;
1919        TResultColumn columnStar = null;
1920
1921
1922
1923        TResultColumn c = null;
1924        if ( (c=  this.getExpandedResultColumns().get(IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,pColumn.getColumnNameOnly()))) != null)
1925        {
1926            //System.out.println("Found:"+pColumn.toString());
1927            pColumn.setSourceColumn(c);
1928            c.getTargetColumns().addObjectName(pColumn);
1929
1930            return true;
1931        }else{
1932           // System.out.println("NotCatch:"+pColumn.toString());
1933        }
1934
1935        if (isCombinedQuery()){
1936            boolean lcResult1;//,lcResult2;
1937            // search column in all select
1938            lcResult1 = getFarLeftStmt().searchColumnInResultSet(pColumn,pMustIn);
1939            if (!lcResult1)
1940            lcResult1 = rightStmt.searchColumnInResultSet(pColumn,pMustIn);
1941            return  lcResult1;
1942        }
1943
1944        if (getResultColumnList() == null) return  false;
1945
1946        if (pColumn.toString().endsWith("*")){
1947            // pColumn here is o1.*
1948            // select o1.*, o2.c1
1949            // from (select c123, c345 from some_table) o1, other_table o2
1950            pColumn.setColumnsLinkedToStar(this.getResultColumnList());
1951            return true;
1952        }
1953
1954        // search columns in select list, skip t.* but count it for later use
1955        for(int i=0;i<getResultColumnList().size();i++){
1956            TResultColumn lcField = getResultColumnList().getResultColumn(i);
1957            if (lcField.toString().endsWith("*")){
1958                numOfColumnStar++;
1959                columnStar = lcField;
1960                continue;
1961            }
1962            lcResult = lcField.isMatchedWithResultColumn(this.dbvendor, pColumn);
1963            if (lcResult){
1964                pColumn.setSourceColumn(lcField);
1965                lcField.getTargetColumns().addObjectName(pColumn);
1966                break;
1967            }
1968        }
1969
1970        if (lcResult) return true;
1971
1972//        // search in * column, including t.* and *
1973        for(int i=0;i<getResultColumnList().size();i++){
1974            TResultColumn lcField = getResultColumnList().getResultColumn(i);
1975            if (lcField.toString().endsWith("*")){
1976                // search column in t.*, have to check column in table t
1977                String prefixTableName = "";
1978                if (lcField.toString().endsWith(".*")){
1979                    String[] a = lcField.toString().split("[.]");
1980                    prefixTableName = a[a.length - 2];
1981                }
1982                for(int j=0;j<tables.size();j++){
1983                    lcResult = tables.getTable(j).searchColumn(this,prefixTableName,pColumn,false);
1984                    if (lcResult) {
1985//                        tables.getTable(j).getLinkedColumns().addObjectName(pColumn);
1986//                        pColumn.setSourceTable(tables.getTable(j));
1987                        pColumn.setSourceColumn(lcField);
1988                        lcField.getTargetColumns().addObjectName(pColumn);
1989                        break;
1990                    }
1991                }
1992            }else{
1993                continue;
1994            }
1995            if (lcResult) break;
1996        }
1997
1998        if (lcResult) return true;
1999
2000        if (pMustIn){
2001            if (tables.size() == 1){ // only a single table in from clause
2002                lcResult = true;
2003                boolean inStarColumn = false;
2004//                tables.getTable(0).getLinkedColumns().addObjectName(pColumn);
2005//                pColumn.setSourceTable(tables.getTable(0));
2006                for(int i=0;i<getResultColumnList().size();i++) {
2007                    TResultColumn lcField = getResultColumnList().getResultColumn(i);
2008                    if (lcField.toString().endsWith("*")) {
2009                        String prefixTableName = "";
2010                        if (lcField.toString().endsWith(".*")){
2011                            String[] a = lcField.toString().split("[.]");
2012                            prefixTableName = a[a.length - 2];
2013                        }
2014                        tables.getTable(0).searchColumn(this,prefixTableName,pColumn,true);
2015                        pColumn.setSourceColumn(lcField);
2016                        lcField.getTargetColumns().addObjectName(pColumn);
2017                        inStarColumn = true;
2018                        break;
2019                    }
2020                }
2021                if (!inStarColumn){
2022
2023                    if (!locateVariableOrParameter(pColumn)){
2024                        // check variable before raise error
2025
2026                        // raise
2027                        TSyntaxError err = new TSyntaxError(pColumn.getStartToken().toString()
2028                                ,pColumn.getStartToken().lineNo,pColumn.getStartToken().columnNo
2029                                ,String.format("Column %s is not found in subquery",pColumn.toString())
2030                                ,EErrorType.sphint ,TBaseType.MSG_ERROR_COLUMN_NOT_FOUND,this,pColumn.getStartToken().posinlist);
2031                        this.parseerrormessagehandle( err);
2032                    }
2033
2034                }
2035            }else if (numOfColumnStar == 1){// only a single * column in select list, but more than one table in from clause
2036
2037                pColumn.setSourceColumn(columnStar);
2038                columnStar.getTargetColumns().addObjectName(pColumn);
2039                if (columnStar.toString().endsWith(".*")){
2040                    lcResult = true;
2041                    String[] a = columnStar.toString().split("[.]");
2042                    String prefixTableName = a[a.length - 2];
2043                    for(int i=0;i<tables.size();i++){
2044                        if (tables.getTable(i).checkTableByName(prefixTableName)){
2045                            tables.getTable(i).searchColumn(this,prefixTableName,pColumn,true);
2046//                            tables.getTable(i).getLinkedColumns().addObjectName(pColumn);
2047//                            pColumn.setSourceTable(tables.getTable(i));
2048                            pColumn.setSourceColumn(columnStar);
2049                            columnStar.getTargetColumns().addObjectName(pColumn);
2050                            break;
2051                        }
2052                    }
2053                }else{
2054                    lcResult = false;
2055                    // * column, no table prefix, this column can only be in one of tables
2056                    for(int i=0;i<tables.size();i++){
2057                        lcResult = tables.getTable(i).searchColumn(this,"",pColumn,false);
2058                        //tables.getTable(i).getLinkedColumns().addObjectName(pColumn);
2059                        //pColumn.setSourceTable(tables.getTable(i));
2060                        pColumn.setSourceColumn(columnStar);
2061                        columnStar.getTargetColumns().addObjectName(pColumn);
2062                    }
2063                }
2064                if (!lcResult) {
2065                    lcResult = linkToFirstTable(pColumn,0);
2066                }
2067            }else{
2068                // multi tables in from clause and multi * column in select list.
2069                lcResult = linkToFirstTable(pColumn,0);
2070            }
2071        }
2072
2073        return lcResult;
2074
2075        //if (lcResult) return true;
2076
2077        // From now on, let's search in * column, there maybe more than one * column in the select list, such as t1.*, t2.*
2078//        TResultColumn resultColumn = getResultColumnList().getResultColumn(0);
2079//        if ((getResultColumnList().size() == 1) &&(resultColumn.toString().equalsIgnoreCase("*") )){
2080//            // search in * or t1.* in the select list
2081//            int tableCntInFromClause = 0;
2082//            TTable tableInFromClause = null;
2083//            for(int i=0;i<tables.size();i++){
2084//                TTable tn = tables.getTable(i);
2085//                if (tn.getEffectType() == ETableEffectType.tetTeradataReference) continue;
2086//                tableInFromClause = tn;
2087//                tableCntInFromClause++;
2088//            }
2089//            //if (tables.size() == 1){
2090//            if (tableCntInFromClause == 1){
2091//                    //TTable t0 = tables.getTable(0);
2092//                TTable t0 = tableInFromClause;
2093//
2094//                if (t0.isBaseTable()){
2095//                        lcResult = fireOnMetaDatabaseTableColumn(t0.getPrefixServer(),t0.getPrefixDatabase(),t0.getPrefixSchema(),t0.getName(),pColumn.getColumnNameOnly());
2096//                        if (! lcResult) candidateTableCnt++;
2097//                    }else{
2098//                        if (t0.getTableType() == ETableSource.subquery){
2099//                            if (t0.isIncludeColumnAlias()){
2100//                                lcResult = t0.searchColumnInAlias(pColumn);
2101//                            }else{
2102//                                lcResult = t0.getSubquery().searchColumnInResultSet(pColumn,pMustIn);
2103//                                if (! lcResult) candidateTableCnt++;
2104//                            }
2105//                        }else if (t0.isCTEName()){
2106//                            lcResult = t0.getCTE().searchColumnInResultSet(this,t0,pColumn,pMustIn);
2107//                            if (! lcResult) candidateTableCnt++;
2108//                        }
2109//                    }
2110//                    if (pMustIn) lcResult = true;
2111//                    if (lcResult){
2112//                        t0.getLinkedColumns().addObjectName(pColumn);
2113//                        pColumn.setSourceTable(t0);
2114//                        pColumn.setSourceColumn(resultColumn);
2115//                        resultColumn.getTargetColumns().addObjectName(pColumn);
2116//                    }
2117//            }else{ // more than one table
2118//                    candidateTableCnt = 0;
2119//                    for(int i=0;i<tables.size();i++){
2120//                        TTable tn = tables.getTable(i);
2121//                        if (tn.isBaseTable()){
2122//                            lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly());
2123//                            if (!lcResult) candidateTableCnt++;
2124//                        }else{
2125//                            if (tn.getTableType() == ETableSource.subquery){
2126//                                if (tn.isIncludeColumnAlias()){
2127//                                    lcResult = tn.searchColumnInAlias(pColumn);
2128//                                }else{
2129//                                    lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,false);
2130//                                    if (!lcResult) candidateTableCnt++;
2131//                                }
2132//                            }else if (tn.isCTEName()){
2133//                                lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,false);
2134//                                if (!lcResult) candidateTableCnt++;
2135//                            }
2136//                        }
2137//
2138//                        if (lcResult){
2139//                            tn.getLinkedColumns().addObjectName(pColumn);
2140//                            pColumn.setSourceTable(tn);
2141//                            pColumn.setSourceColumn(resultColumn);
2142//                            resultColumn.getTargetColumns().addObjectName(pColumn);
2143//                            break;
2144//                        }
2145//                    }
2146//                    if ((!lcResult) && (pMustIn)) linkToFirstTable(pColumn,candidateTableCnt);
2147//            }
2148//           // }
2149//        }
2150//
2151//        if (lcResult) return true;
2152//
2153//        // search t.*
2154//        //int starColumnPos = 0,
2155//        int numOfTableDotStar=0;
2156//        for (int i=0;i<getResultColumnList().size();i++){
2157//            if (getResultColumnList().getResultColumn(i).toString().endsWith(".*")){
2158//                numOfTableDotStar++;
2159//            }
2160//        }
2161//
2162//        TResultColumn rc = null;
2163//        TTable tn = null;
2164//        for (int i=0;i<getResultColumnList().size();i++){
2165//            if (!getResultColumnList().getResultColumn(i).toString().endsWith(".*")) continue;
2166//            rc = getResultColumnList().getResultColumn(i);
2167//          //  starColumnPos = i;
2168//
2169//            for (int j=0;j<tables.size();j++){
2170//                if (! tables.getTable(j).equalByName(rc.getPrefixTable())) continue;
2171//                tn = tables.getTable(j);
2172//
2173//                if (tn.isBaseTable()){
2174//                    lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly());
2175//                    if (!lcResult) candidateTableCnt++;
2176//                }else{
2177//                    if (tn.getTableType() == ETableSource.subquery){
2178//                        if (tn.isIncludeColumnAlias()){
2179//                            lcResult = tn.searchColumnInAlias(pColumn);
2180//                        }else{
2181//                            lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,((pMustIn)&&(numOfTableDotStar == 1)));
2182//                            if (!lcResult) candidateTableCnt++;
2183//                        }
2184//                    }else if (tn.isCTEName()){
2185//                        lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,((pMustIn)&&(numOfTableDotStar == 1)));
2186//                        if (!lcResult) candidateTableCnt++;
2187//                    }
2188//                }
2189//
2190//                if (lcResult){
2191//                    tn.getLinkedColumns().addObjectName(pColumn);
2192//                    pColumn.setSourceTable(tn);
2193//                    pColumn.setSourceColumn(rc);
2194//                    rc.getTargetColumns().addObjectName(pColumn);
2195//                    break;
2196//                }
2197//            }
2198//            if (lcResult) break;
2199//        }
2200//
2201//        if (lcResult) return true;
2202//
2203//        if ((pMustIn) && (numOfTableDotStar == 1) && (tn != null)){
2204//            tn.getLinkedColumns().addObjectName(pColumn);
2205//            pColumn.setSourceTable(tn);
2206//            pColumn.setSourceColumn(rc);
2207//            rc.getTargetColumns().addObjectName(pColumn);
2208//            lcResult = true;
2209//        }
2210//
2211//        if (lcResult) return true;
2212//
2213//        if ((pMustIn) && (numOfTableDotStar > 0)) lcResult = linkToFirstTable(pColumn,candidateTableCnt);
2214//
2215//        if ((pMustIn)&&(!lcResult)) try {
2216//            throw new Exception(" column must be found in the select list:"+pColumn.toString());
2217//        } catch (Exception e) {
2218//            e.printStackTrace();
2219//        }
2220//
2221//        return lcResult;
2222    }
2223
2224
2225}