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
958        if ((rootNode instanceof TSelectSqlNode)
959                && (this.sourcetokenlist.size() == 0)){
960            // subquery nested in other statements.
961            TSelectSqlNode selectNode = (TSelectSqlNode)rootNode;
962            this.setStartToken(selectNode.getStartToken());
963            this.setEndToken(selectNode.getEndToken());
964        }
965
966        super.doParseStatement(psql);
967
968        if (!(rootNode instanceof TSelectSqlNode)) {
969            return reportInvalidSelectStatement();
970        }
971
972        TSelectSqlNode selectNode = (TSelectSqlNode)rootNode;
973        if (hasInvalidResultColumnList(selectNode, psql)) {
974            return reportInvalidSelectStatement();
975        }
976
977        this.selectToken = selectNode.getSelectToken();
978        parenthesisCount = selectNode.getParenthesisCount();
979        parenthesisCountBeforeOrder = selectNode.getParenthissisCountBeforeOrder();
980
981        setOperator = selectNode.getSetOperator();
982        initSetOperatorFields();
983
984        if(selectNode.isCombinedQuery()){
985            TCustomSqlStatement lcParentSql = psql;
986            if ((lcParentSql == null)||(!childOfCombinedQuery)){
987                lcParentSql = this;
988            }
989
990            if (selectNode.cteList != null){
991                this.setCteList(selectNode.cteList);
992                for(int i=0;i<getCteList().size();i++){
993                    getCteList().getCTE(i).doParse(this,ESqlClause.cte);
994                }
995            }
996
997            // Oracle 12c WITH FUNCTION/PROCEDURE support
998            if (selectNode.getWithPlsqlItems() != null){
999                this.setWithPlsqlItems(selectNode.getWithPlsqlItems());
1000            }
1001
1002            // Iterative construction of the left-recursive UNION/INTERSECT/EXCEPT chain.
1003            // This avoids StackOverflow for queries with many set operations (e.g., 2000+ UNION ALL).
1004            // We collect the chain of combined query nodes, set up their properties top-down,
1005            // then process leaf children and clauses from deepest to shallowest.
1006
1007            ArrayList<TSelectSqlStatement> stmtChain = new ArrayList<>();
1008            ArrayList<TSelectSqlNode> nodeChain = new ArrayList<>();
1009
1010            stmtChain.add(this);
1011            nodeChain.add(selectNode);
1012
1013            TSelectSqlStatement currentStmt = this;
1014            TSelectSqlNode currentNode = selectNode;
1015
1016            // Walk down the left chain, creating intermediate TSelectSqlStatements
1017            while (currentNode.getLeftNode() != null && currentNode.getLeftNode().isCombinedQuery()) {
1018                TSelectSqlNode leftNode = currentNode.getLeftNode();
1019
1020                TSelectSqlStatement nextStmt = new TSelectSqlStatement(dbvendor);
1021                nextStmt.rootNode = leftNode;
1022                nextStmt.setChildOfCombinedQuery(true);
1023
1024                // Wire up parent's leftStmt
1025                currentStmt.leftStmt = nextStmt;
1026
1027                // Inline common setup (equivalent of super.doParseStatement + field init)
1028                if (nextStmt.sourcetokenlist.size() == 0) {
1029                    nextStmt.setStartToken(leftNode.getStartToken());
1030                    nextStmt.setEndToken(leftNode.getEndToken());
1031                }
1032                // Equivalent of TCustomSqlStatement.doParseStatement(lcParentSql)
1033                nextStmt.setParentStmt(lcParentSql);
1034                nextStmt.setFrameStack(lcParentSql.getFrameStack());
1035                lcParentSql.getStmtScope().incrementCurrentStmtIndex();
1036                nextStmt.setQueryId(String.format("%s#stmt_%d_%s",
1037                        lcParentSql.getQueryId(),
1038                        lcParentSql.getStmtScope().getCurrentStmtIndex(),
1039                        nextStmt.sqlstatementtype));
1040                nextStmt.setStmtScope(new TStmtScope(lcParentSql.getStmtScope(), nextStmt));
1041                if (nextStmt.getStartToken() == null && nextStmt.rootNode != null) {
1042                    nextStmt.setStartToken(nextStmt.rootNode.getStartToken());
1043                }
1044                if (nextStmt.getEndToken() == null && nextStmt.rootNode != null) {
1045                    nextStmt.setEndToken(nextStmt.rootNode.getEndToken());
1046                }
1047                if (nextStmt.getGsqlparser() == null && nextStmt.rootNode != null) {
1048                    nextStmt.setGsqlparser(nextStmt.rootNode.getGsqlparser());
1049                }
1050
1051                nextStmt.selectToken = leftNode.getSelectToken();
1052                nextStmt.parenthesisCount = leftNode.getParenthesisCount();
1053                nextStmt.parenthesisCountBeforeOrder = leftNode.getParenthissisCountBeforeOrder();
1054                nextStmt.setOperator = leftNode.getSetOperator();
1055                nextStmt.initSetOperatorFields();
1056
1057                stmtChain.add(nextStmt);
1058                nodeChain.add(leftNode);
1059
1060                currentStmt = nextStmt;
1061                currentNode = leftNode;
1062            }
1063
1064            // Create and process the leftmost leaf (non-combined SELECT)
1065            TSelectSqlStatement leftmostLeaf = new TSelectSqlStatement(dbvendor);
1066            leftmostLeaf.rootNode = currentNode.getLeftNode();
1067            leftmostLeaf.setChildOfCombinedQuery(true);
1068            currentStmt.leftStmt = leftmostLeaf;
1069            leftmostLeaf.doParseStatement(lcParentSql);
1070
1071            // Process right children and clauses from deepest to shallowest
1072            for (int i = stmtChain.size() - 1; i >= 0; i--) {
1073                TSelectSqlStatement stmt = stmtChain.get(i);
1074                TSelectSqlNode node = nodeChain.get(i);
1075
1076                // Create and process right child (always a leaf for left-recursive grammar)
1077                stmt.rightStmt = new TSelectSqlStatement(dbvendor);
1078                stmt.rightStmt.rootNode = node.getRightNode();
1079                stmt.rightStmt.setChildOfCombinedQuery(true);
1080                stmt.rightStmt.doParseStatement(lcParentSql);
1081
1082                // Handle clauses for this level
1083                if (node.getOrderbyClause() != null) {
1084                    node.getOrderbyClause().doParse(stmt, ESqlClause.orderby);
1085                    stmt.orderbyClause = node.getOrderbyClause();
1086                }
1087                stmt.limitClause = node.getLimitClause();
1088                if (node.getForupdateClause() != null) {
1089                    node.getForupdateClause().doParse(stmt, ESqlClause.forUpdate);
1090                    stmt.forUpdateClause = node.getForupdateClause();
1091                }
1092                if (node.getComputeClause() != null) {
1093                    node.getComputeClause().doParse(stmt, ESqlClause.compute);
1094                    stmt.computeClause = node.getComputeClause();
1095                }
1096                stmt.optionClause = node.getOptionClause();
1097                stmt.timeTravel = node.getTimeTravel();
1098                stmt.hintClause = node.getHintClause();
1099            }
1100
1101            return 0;
1102        }
1103
1104        if (selectNode.getValueClause() != null){
1105            this.valueClause = selectNode.getValueClause();
1106            this.valueClause.doParse(this,ESqlClause.selectValue);
1107            isValueClause = true;
1108            return 0;
1109        }
1110
1111        if (selectNode.getTransformClause() != null){
1112            this.transformClause = selectNode.getTransformClause();
1113            this.transformClause.doParse(this,ESqlClause.transformClause);
1114        }
1115
1116        if (selectNode.cteList != null){
1117            this.setCteList(selectNode.cteList);
1118            this.getCteList().doParse(this,ESqlClause.cte);
1119        }
1120
1121        // Oracle 12c WITH FUNCTION/PROCEDURE support
1122        if (selectNode.getWithPlsqlItems() != null){
1123            this.setWithPlsqlItems(selectNode.getWithPlsqlItems());
1124        }
1125
1126        if (selectNode.isHiveFromQuery()){
1127            if(selectNode.getSelectSqlNodes() != null){
1128                for(int i=1;i<selectNode.getSelectSqlNodes().size();i++){
1129                    //start from the second, the first select statement is represented by this class instance.
1130
1131                    TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive);
1132                    select.rootNode = selectNode.getSelectSqlNodes().get(i);
1133                    select.doParseStatement(this);
1134                    this.getMultiSelectStatements().add(select);
1135                }
1136            }
1137
1138            // Hive: from query insert...
1139//            if (selectNode.getFromTableList() != null){
1140//                TFromTable lcFromTable;
1141//                TJoin lcJoin;
1142//
1143//                for(int i=0; i<selectNode.getFromTableList().size();i++){
1144//                    lcFromTable = selectNode.getFromTableList().getFromTable(i);
1145//                    TTable lcTable = null;
1146//
1147//                    if (lcFromTable.getFromtableType() != ETableSource.join){
1148//                        lcJoin = new TJoin();
1149//                        lcTable = analyzeFromTable(lcFromTable,true);
1150//                        lcTable.setEffectType(ETableEffectType.tetSelect);
1151//                        lcJoin.setTable(lcTable);
1152//                        lcJoin.setStartToken(lcJoin.getTable().getStartToken());
1153//                        lcJoin.setEndToken(lcJoin.getTable().getEndToken());
1154//                        lcJoin.setGsqlparser(getGsqlparser());
1155//                    }else{
1156//                        lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
1157//                        lcJoin.doParse(this, ESqlClause.join);
1158//
1159//                        if (lcFromTable.getLateralViewList() != null){
1160//                            for(TLateralView lateralView:lcFromTable.getLateralViewList()){
1161//                                addToTables(lateralView.createATable(this));
1162//                            }
1163//                        }
1164//                    }
1165//
1166//                    joins.addJoin(lcJoin);
1167//                }
1168//            }
1169
1170
1171//            if (selectNode.getHiveBodyList() != null){
1172//                for(int i = 0; i<selectNode.getHiveBodyList().size();i++){
1173//                    TParseTreeNode node1 = selectNode.getHiveBodyList().get(i);
1174//                    switch (node1.getNodeType()){
1175//                        case TStatementSqlNode.select:
1176//                            TSelectSqlStatement select = new TSelectSqlStatement(EDbVendor.dbvhive);
1177//                            select.rootNode = node1;
1178//                            select.doParseStatement(this);
1179//                            this.getHiveBodyList().add(select);
1180//
1181//                            break;
1182//                        case TStatementSqlNode.insert:
1183//
1184//                            TInsertSqlStatement insert = new TInsertSqlStatement(EDbVendor.dbvhive);
1185//                            insert.rootNode = node1;
1186//                            insert.doParseStatement(this);
1187//                            this.getHiveBodyList().add(insert);
1188//                            break;
1189//                        default:
1190//                            break;
1191//                    }
1192//                }
1193//            }
1194           // return 0;
1195        }
1196
1197        // get oracle hint
1198        if((dbvendor == EDbVendor.dbvoracle)||(dbvendor == EDbVendor.dbvmysql)){
1199            TSourceToken lcnextst = this.selectToken.container.nextsolidtoken(this.selectToken.posinlist,1,true);
1200            while (lcnextst != null){
1201                if (!((lcnextst.tokentype == ETokenType.ttsimplecomment) || (lcnextst.tokentype == ETokenType.ttbracketedcomment))) break;
1202
1203                if (lcnextst.tokentype == ETokenType.ttbracketedcomment){
1204                    if (lcnextst.toString().startsWith("/*+")){
1205                       //lcnextst.setDbObjType(TObjectName.ttObjOracleHint);
1206                       lcnextst.setDbObjectType(EDbObjectType.oracleHint);
1207                       if (oracleHint == null){
1208                           oracleHint = lcnextst.toString();
1209                       }else {
1210                           oracleHint = oracleHint + " " + lcnextst.toString();
1211                       }
1212                    }
1213                }
1214
1215                if (lcnextst.tokentype == ETokenType.ttsimplecomment){
1216                    if (lcnextst.toString().startsWith("--+")){
1217                       //lcnextst.setDbObjType(TObjectName.ttObjOracleHint);
1218                        lcnextst.setDbObjectType(EDbObjectType.oracleHint);
1219                       if (oracleHint == null){
1220                           oracleHint = lcnextst.toString();
1221                       }else {
1222                           oracleHint = oracleHint + " " + lcnextst.toString();
1223                       }
1224                    }
1225                }
1226
1227                lcnextst = lcnextst.container.nextsolidtoken(lcnextst,1,true);
1228            }
1229
1230            hint = oracleHint;
1231        }
1232
1233        if (selectNode.getHiveHintClause() != null){
1234            hiveHintClause = selectNode.getHiveHintClause();
1235        }
1236
1237        isConsume = selectNode.isConsume();
1238
1239        if (selectNode.getTopClause() != null){
1240           selectNode.getTopClause().doParse(this,ESqlClause.top);
1241            this.setTopClause(selectNode.getTopClause()); 
1242        }
1243
1244 //       this.skipOffset = selectNode.getSkipOffset();
1245//        this.firstMax = selectNode.getFirstMax();
1246//        this.limitMax = selectNode.getLimitMax();
1247
1248        if (selectNode.getSelectDistinct() != null){
1249            this.selectDistinct = selectNode.getSelectDistinct();
1250        }
1251
1252        this.selectModifiers = selectNode.getSelectModifiers();
1253
1254        TFromTable lcFromTable = null;
1255        TJoin lcJoin = null;
1256
1257        if (selectNode.getFromTableList() != null){
1258            fromClause = new TFromClause(this.getRelations());
1259            fromClause.setStartToken(selectNode.getFromTableList().getStartToken());
1260            fromClause.setEndToken(selectNode.getFromTableList().getEndToken());
1261
1262            for(int i=0; i<selectNode.getFromTableList().size();i++){
1263                 lcFromTable = selectNode.getFromTableList().getFromTable(i);
1264                 lcJoin = analyzeTableOrJoin(lcFromTable);
1265                 joins.addJoin(lcJoin);
1266            }
1267        }
1268
1269        // ClickHouse expression-CTEs (WITH <expr> AS ident) are evaluated in
1270        // this statement's own scope, so their column references can only
1271        // link once the FROM clause above has populated tables — the
1272        // cteList.doParse earlier in this method runs before that.
1273        if ((dbvendor == EDbVendor.dbvclickhouse) && (this.getCteList() != null)){
1274            for(int i=0;i<getCteList().size();i++){
1275                TCTE lcCte = getCteList().getCTE(i);
1276                if (lcCte.getExpression() != null){
1277                    lcCte.getExpression().doParse(this,ESqlClause.cte);
1278                }
1279            }
1280        }
1281
1282        // Publish the hierarchical clause before the select list is parsed.
1283        // doParse() for the clause itself still runs in its usual place below;
1284        // this only makes getHierarchicalClause() answer truthfully while the
1285        // result columns are being linked, which is when
1286        // TCustomSqlStatement.isOraclePseudoColumnReference() needs to know
1287        // whether CONNECT_BY_ISLEAF / CONNECT_BY_ISCYCLE are pseudocolumns
1288        // here or ordinary identifiers (Mantis #4675).
1289        if (selectNode.getHierarchicalClause() != null){
1290            this.hierarchicalClause = selectNode.getHierarchicalClause();
1291        }
1292
1293        if (selectNode.getResultColumnList() != null){
1294            this.setResultColumnList(selectNode.getResultColumnList());
1295
1296//            if ((this.getResultColumnList().size() > 10)
1297//                    &&(this.getTables().size() == 1)
1298//                    &&(this.getTables().getTable(0).getTableType() == ETableSource.subquery)
1299//                    &&( this.getTables().getTable(0).getSubquery().getResultColumnList().size() == this.getResultColumnList().size() )
1300//            ){
1301//                TTable t0 = this.getTables().getTable(0);
1302//                ArrayList<TResultColumn> targetColumnArrayList = this.getResultColumnList().getSortedColumns();
1303//                ArrayList<TResultColumn> sourceColumnArrayList = t0.getSubquery().getResultColumnList().getSortedColumns();
1304//                int i=0;
1305//                for(TResultColumn rc:targetColumnArrayList){
1306//                    TObjectName targetColumn = rc.getExpr().getObjectOperand();
1307//                    TResultColumn sourceResultColumn = sourceColumnArrayList.get(i++);
1308//                    //TObjectName sourceColumn = sourceResultColumn.getExpr().getObjectOperand();
1309//                    if (targetColumn != null){
1310//                        //System.out.println(targetColumn+"\t->\t"+sourceResultColumn.getDisplayName());
1311//                        targetColumn.setSourceTable(t0);
1312//                        t0.getLinkedColumns().addObjectName(targetColumn);
1313//                        targetColumn.setSourceColumn(sourceResultColumn);
1314//                        sourceResultColumn.getTargetColumns().addObjectName(targetColumn);
1315//                    }
1316//                }
1317//            }
1318
1319            selectNode.getResultColumnList().doParse(this,ESqlClause.selectList);
1320
1321            // Slice 73: link DISTINCT ON expression list (PostgreSQL /
1322            // Greenplum `SELECT DISTINCT ON (cols) ...`) so each
1323            // TObjectName inside gets dbObjectType=column and
1324            // sourceTable populated. Without this, the expressions
1325            // remain EDbObjectType.unknown. The legacy column-linker
1326            // (linkColumnToTable) is invoked here via TExpression.doParse;
1327            // resolver-2 picks the same expressions up via the
1328            // TSelectDistinct.acceptChildren descent that slice 73
1329            // also wires up. Tables are populated by the FROM clause
1330            // loop above so column linking has a relation list to
1331            // resolve against. Mirrors the TGroupBy.doParse →
1332            // items.doParse pattern.
1333            if (this.selectDistinct != null
1334                    && this.selectDistinct.getExpressionList() != null) {
1335                TExpressionList distinctOnExprList =
1336                        this.selectDistinct.getExpressionList();
1337                for (int i = 0; i < distinctOnExprList.size(); i++) {
1338                    TExpression e = distinctOnExprList.getExpression(i);
1339                    if (e != null) {
1340                        e.doParse(this, ESqlClause.unknown);
1341                    }
1342                }
1343            }
1344
1345            for(int i=0;i<selectNode.getResultColumnList().size();i++){
1346                TResultColumn resultColumn = selectNode.getResultColumnList().getResultColumn(i);
1347                TExpression expression = resultColumn.getExpr();
1348                String expressionText = expression.toString();
1349                if (expressionText.endsWith("*")){
1350                    TTable starSourceTable = null;
1351                    //System.out.println(resultColumn.toString()+":"+resultColumn.getStartToken().lineNo+","+resultColumn.getStartToken().columnNo);
1352                    if (expressionText.startsWith("*")){
1353                        // add all result columns in from tables
1354                        for(int j=0;j<getTables().size();j++){
1355                            if (getTables().getTable(j).getTableType() == ETableSource.subquery){
1356                                getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns());
1357                            }else{
1358                                // ToDo for real table
1359                            }
1360                            //System.out.println("\t"+getTables().getTable(j).toString()+",\t"+getTables().getTable(j).getTableType()+",\t"+getTables().getTable(j).isCTEName());
1361                        }
1362                        if (getTables().size() == 1){
1363                            starSourceTable = getTables().getTable(0);
1364                        }
1365
1366                    }else{
1367                        for(int j=0;j<getTables().size();j++){
1368                            if (getTables().getTable(j).getAliasName().equalsIgnoreCase( resultColumn.toString().split("[.]")[0])){
1369                                if (getTables().getTable(j).getTableType() == ETableSource.subquery){
1370                                    getExpandedResultColumns().putAll(getTables().getTable(j).getSubquery().getExpandedResultColumns());
1371                                }else{
1372                                    // ToDo for real table
1373                                }
1374                                starSourceTable = getTables().getTable(j);
1375                                break;
1376                            }
1377                        }
1378                    }
1379                    if (starSourceTable != null) {
1380                        TObjectName objectOperand = expression.getObjectOperand();
1381                        if (objectOperand == null) {
1382                            return reportInvalidSelectStatement();
1383                        }
1384                        objectOperand.setSourceTable(starSourceTable);
1385                    }
1386                }else{
1387                    String expandedKey = IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,resultColumn.getDisplayName());
1388                    if (expandedKey == null){
1389                        return reportInvalidSelectStatement();
1390                    }
1391                    getExpandedResultColumns().put(expandedKey,resultColumn);
1392                }
1393            }
1394        }
1395
1396        if (selectNode.getIntoClause() != null){
1397            this.intoClause = selectNode.getIntoClause();
1398            this.intoClause.doParse(this,ESqlClause.selectInto);
1399        }
1400
1401
1402        if (selectNode.getWhereCondition() != null){
1403            selectNode.getWhereCondition().doParse(this,ESqlClause.where);
1404            this.setWhereClause( selectNode.getWhereCondition());
1405        }
1406
1407        if (selectNode.getHierarchicalClause() != null){
1408         selectNode.getHierarchicalClause().doParse(this,ESqlClause.hierarchical);
1409         this.hierarchicalClause = selectNode.getHierarchicalClause();
1410        }
1411
1412        if (selectNode.getGroupByClause() != null){
1413            selectNode.getGroupByClause().doParse(this,ESqlClause.groupby);
1414            this.groupByClause = selectNode.getGroupByClause(); 
1415        }
1416
1417        if (selectNode.getQualifyClause() != null){
1418            selectNode.getQualifyClause().doParse(this,ESqlClause.qualify);
1419            this.qualifyClause = selectNode.getQualifyClause(); 
1420        }
1421
1422        if (selectNode.getSampleClause() != null){
1423            selectNode.getSampleClause().doParse(this,ESqlClause.sample);
1424            this.sampleClause = selectNode.getSampleClause();
1425        }
1426
1427        if (selectNode.getExpandOnClause() != null){
1428            selectNode.getExpandOnClause().doParse(this,ESqlClause.expandOn);
1429            this.expandOnClause = selectNode.getExpandOnClause();
1430        }
1431
1432        if (selectNode.getWithClause() != null){
1433            selectNode.getWithClause().doParse(this,ESqlClause.teradataWith);
1434            this.teradataWithClause  = selectNode.getWithClause();
1435        }
1436
1437        if (selectNode.getOrderbyClause() != null){
1438            selectNode.getOrderbyClause().doParse(this,ESqlClause.orderby);
1439            this.orderbyClause = selectNode.getOrderbyClause(); 
1440        }
1441
1442        if (selectNode.getLockingClauses() != null){
1443           selectNode.getLockingClauses().doParse(this,ESqlClause.lockingClause);
1444            this.lockingClauses = selectNode.getLockingClauses();
1445        }
1446
1447        this.sortBy = selectNode.getSortBy();
1448        if (this.sortBy != null){
1449            this.sortBy.doParse(this,ESqlClause.sortby);
1450        }
1451
1452        this.clusterBy = selectNode.getClusterBy();
1453        if (this.clusterBy != null){
1454            this.clusterBy.doParse(this,ESqlClause.cluster);
1455        }
1456
1457        this.windowClause = selectNode.getWindowClause();
1458        if (this.windowClause != null){
1459            this.windowClause.doParse(this,ESqlClause.windowClause);
1460        }
1461        this.limitClause = selectNode.getLimitClause();
1462        if (this.limitClause != null){
1463            this.limitClause.doParse(this,ESqlClause.limit);
1464        }
1465
1466       if (selectNode.getForupdateClause() != null){
1467            selectNode.getForupdateClause().doParse(this,ESqlClause.forUpdate);
1468            this.forUpdateClause  = selectNode.getForupdateClause();
1469        }
1470
1471        if (selectNode.getComputeClause() != null){
1472            selectNode.getComputeClause().doParse(this,ESqlClause.compute);
1473            this.computeClause = selectNode.getComputeClause(); 
1474        }
1475
1476        this.intoTableClause = selectNode.getIntoTableClause();
1477
1478        if (selectNode.getDistributeBy() != null){
1479            this.distributeBy = selectNode.getDistributeBy();
1480            this.distributeBy.doParse(this,ESqlClause.distributeBy);
1481        }
1482
1483
1484        this.isolationClause = selectNode.getIsolationClause();
1485
1486        this.optionClause = selectNode.getOptionClause();
1487
1488        this.offsetClause = selectNode.getOffsetClause();
1489        this.fetchFirstClause = selectNode.getFetchFirstClause();
1490
1491        this.timeTravel = selectNode.getTimeTravel();
1492        this.hintClause = selectNode.getHintClause();
1493
1494        if (selectNode.getForXMLClause() != null){
1495            if (tables.size() > 0){
1496                tables.getTable(0).setForXMLClause(selectNode.getForXMLClause());
1497            }
1498        }
1499
1500        // StarRocks pipe operator support
1501        this.pipeOperators = selectNode.getPipeOperators();
1502        this.isPipeQuery = selectNode.isPipeQuery();
1503
1504        return 0;
1505    }
1506
1507    private boolean hasInvalidResultColumnList(TSelectSqlNode selectNode,
1508            TCustomSqlStatement psql) {
1509        TResultColumnList resultColumns = selectNode.getResultColumnList();
1510        if (resultColumns == null) {
1511            return false;
1512        }
1513
1514        for (int i = 0; i < resultColumns.size(); i++) {
1515            TResultColumn resultColumn = resultColumns.getResultColumn(i);
1516            if ((resultColumn == null) || (resultColumn.getExpr() == null)) {
1517                return true;
1518            }
1519
1520            TExpression expression = resultColumn.getExpr();
1521            String expressionText = expression.toString();
1522            if (expressionText == null) {
1523                return true;
1524            }
1525            if (!expressionText.endsWith("*")
1526                    && (resultColumn.getDisplayName() == null)) {
1527                return true;
1528            }
1529        }
1530
1531        if (((dbvendor == EDbVendor.dbvmssql)
1532                || (dbvendor == EDbVendor.dbvoracle))
1533                && (psql instanceof TInsertSqlStatement)
1534                && (resultColumns.getEndToken() != null)
1535                && (resultColumns.getEndToken().container != null)) {
1536            TSourceToken resultListEnd = resultColumns.getEndToken();
1537            TSourceToken nextToken = resultListEnd.container
1538                    .nextsolidtoken(resultListEnd, 1, true);
1539            if ((nextToken != null) && (nextToken.tokencode == ',')) {
1540                TSourceToken tokenAfterComma = nextToken.container
1541                        .nextsolidtoken(nextToken, 1, true);
1542                if ((tokenAfterComma != null)
1543                        && (tokenAfterComma.tokencode == TBaseType.rrw_from)) {
1544                    return true;
1545                }
1546            }
1547        }
1548
1549        return false;
1550    }
1551
1552    private int reportInvalidSelectStatement() {
1553        TSourceToken errorToken = rootNode.getStartToken();
1554        if ((errorToken == null) && (sourcetokenlist.size() > 0)) {
1555            errorToken = sourcetokenlist.get(0);
1556        }
1557        if (errorToken != null) {
1558            parseerrormessagehandle(new TSyntaxError(errorToken,
1559                    "invalid SELECT statement", EErrorType.sperror,
1560                    TBaseType.MSG_ERROR_SYNTAX_ERROR, this));
1561        } else {
1562            parseerrormessagehandle(new TSyntaxError("SELECT", 0, 0,
1563                    "invalid SELECT statement", EErrorType.sperror,
1564                    TBaseType.MSG_ERROR_SYNTAX_ERROR, this, -1));
1565        }
1566        return TBaseType.MSG_ERROR_SYNTAX_ERROR;
1567    }
1568
1569    /**
1570     * Determine whether The UNION, EXCEPT and INTERSECT operators were used.
1571     * @return true if one of those operators were used.
1572     */
1573    public boolean isCombinedQuery(){
1574    // combine multiple queries using the set operators UNION, UNION ALL, INTERSECT, and MINUS.
1575        return (setOperator > 0);
1576    }
1577
1578    /**
1579     * Initialize setOperatorType, all, and setOpDistinct fields from setOperator value.
1580     * Used by doParseStatement's iterative combined query construction.
1581     */
1582    private void initSetOperatorFields() {
1583        switch (setOperator) {
1584            case SET_OPERATOR_NONE:
1585                setOperatorType = ESetOperatorType.none; all = false; break;
1586            case setOperator_union:
1587                setOperatorType = ESetOperatorType.union; all = false; break;
1588            case setOperator_unionall:
1589                setOperatorType = ESetOperatorType.union; all = true; break;
1590            case SET_OPERATOR_UNIONDISTINCT:
1591                setOperatorType = ESetOperatorType.union; setOpDistinct = true; break;
1592            case setOperator_intersect:
1593                setOperatorType = ESetOperatorType.intersect; all = false; break;
1594            case setOperator_intersectall:
1595                setOperatorType = ESetOperatorType.intersect; all = true; break;
1596            case setOperator_except:
1597                setOperatorType = ESetOperatorType.except; all = false; break;
1598            case setOperator_exceptall:
1599                setOperatorType = ESetOperatorType.except; all = true; break;
1600            case setOperator_minus:
1601                setOperatorType = ESetOperatorType.minus; all = false; break;
1602            case setOperator_minusall:
1603                setOperatorType = ESetOperatorType.minus; all = true; break;
1604            case SET_OPERATOR_INTERSECTDISTINCT:
1605                setOperatorType = ESetOperatorType.intersect; setOpDistinct = true; break;
1606            case SET_OPERATOR_EXCEPTDISTINCT:
1607                setOperatorType = ESetOperatorType.except; setOpDistinct = true; break;
1608        }
1609    }
1610
1611    public void accept(TParseTreeVisitor v)
1612    {
1613        v.preVisit(this);
1614        v.postVisit(this);
1615    }
1616
1617    /**
1618     * Accept visitor to visit this class.
1619     * @param v user defined visitor.
1620     */
1621    public void acceptChildren(TParseTreeVisitor v)
1622    {
1623
1624        if(this.isCombinedQuery()){
1625
1626            // Iterative traversal for combined queries to avoid StackOverflow
1627            // on deeply nested left-recursive UNION/INTERSECT/EXCEPT chains.
1628            // Collect the left-recursive chain of combined query nodes.
1629            ArrayList<TSelectSqlStatement> chain = new ArrayList<>();
1630            TSelectSqlStatement current = this;
1631            while (current.isCombinedQuery()) {
1632                chain.add(current);
1633                current = current.getLeftStmt();
1634            }
1635            // 'current' is now the leftmost leaf (non-combined SELECT)
1636
1637            // Phase 1: preVisit all combined nodes and their CTEs, from root to deepest
1638            for (int i = 0; i < chain.size(); i++) {
1639                TSelectSqlStatement node = chain.get(i);
1640                v.preVisit(node);
1641                if (node.getCteList() != null) {
1642                    node.getCteList().acceptChildren(v);
1643                }
1644            }
1645
1646            // Phase 2: Visit leftmost leaf SELECT
1647            current.acceptChildren(v);
1648
1649            // Phase 3: Visit right branches and postVisit, from deepest to root
1650            for (int i = chain.size() - 1; i >= 0; i--) {
1651                TSelectSqlStatement node = chain.get(i);
1652                node.getRightStmt().acceptChildren(v);
1653
1654                if (node.getOrderbyClause() != null) {
1655                    node.getOrderbyClause().acceptChildren(v);
1656                }
1657                if (node.getLimitClause() != null) {
1658                    node.getLimitClause().acceptChildren(v);
1659                }
1660                if (node.getForUpdateClause() != null) {
1661                    node.getForUpdateClause().acceptChildren(v);
1662                }
1663                if (node.getComputeClause() != null) {
1664                    node.getComputeClause().acceptChildren(v);
1665                }
1666                v.postVisit(node);
1667            }
1668
1669            return ;
1670        }
1671
1672        // System.out.println(this.toString().hashCode()+" "+ this.toString().substring(0,50));
1673
1674        v.preVisit(this);
1675
1676        if (this.getTransformClause() != null){
1677            this.getTransformClause().acceptChildren(v);
1678        }
1679
1680        if (this.getCteList() != null){
1681            this.getCteList().acceptChildren(v);
1682        }
1683
1684        if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){
1685//            fromClause.acceptChildren(v);
1686            v.preVisit(fromClause);
1687            for(TTable table:getRelations()){
1688                table.acceptChildren(v);
1689            }
1690            v.postVisit(fromClause);
1691        }else{
1692            if (this.getJoins() != null){
1693                this.getJoins().acceptChildren(v);
1694            }
1695        }
1696
1697        if (this.getHiveHintClause() != null){
1698            this.getHiveHintClause().acceptChildren(v);
1699        }
1700
1701
1702        if (this.getTopClause() != null){
1703            this.getTopClause().acceptChildren(v);
1704        }
1705
1706        if (this.getSelectDistinct() != null){
1707            this.getSelectDistinct().acceptChildren(v);
1708        }
1709        
1710        if (this.getResultColumnList() != null){
1711            this.getResultColumnList().acceptChildren(v);
1712        }
1713
1714        if (this.getIntoClause() != null){
1715            this.getIntoClause().acceptChildren(v);
1716        }
1717
1718
1719        if (this.getWhereClause() != null){
1720            this.getWhereClause().acceptChildren(v);
1721        }
1722
1723        if (this.getHierarchicalClause() != null){
1724            this.getHierarchicalClause().acceptChildren(v);
1725        }
1726
1727        if (this.getGroupByClause() != null){
1728            this.getGroupByClause().acceptChildren(v);
1729        }
1730
1731        if (this.getQualifyClause() != null){
1732            this.getQualifyClause().acceptChildren(v);
1733        }
1734
1735        if (this.getSampleClause() != null){
1736            this.getSampleClause().acceptChildren(v);
1737        }
1738
1739        if (this.getExpandOnClause() != null){
1740            this.getExpandOnClause().acceptChildren(v);
1741        }
1742
1743        if (this.getTeradataWithClause() != null){
1744            this.getTeradataWithClause().acceptChildren(v);
1745        }
1746
1747        if (this.getOrderbyClause() != null){
1748            this.getOrderbyClause().acceptChildren(v);
1749        }
1750
1751        if (this.getLockingClauses() != null){
1752            this.getLockingClauses().acceptChildren(v);
1753        }
1754
1755        if (this.getSortBy() != null){
1756            this.getSortBy().acceptChildren(v);
1757        }
1758
1759        if (this.getClusterBy() != null){
1760            this.getClusterBy().acceptChildren(v);
1761        }
1762
1763        if (this.getWindowClause() != null){
1764            this.getWindowClause().acceptChildren(v);
1765        }
1766
1767        if (this.getLimitClause() != null){
1768            this.getLimitClause().acceptChildren(v);
1769        }
1770
1771        if (this.getForUpdateClause() != null){
1772            this.getForUpdateClause().acceptChildren(v);
1773        }
1774
1775        if (this.getComputeClause() != null){
1776            this.getComputeClause().acceptChildren(v);
1777        }
1778
1779        if (this.getIntoTableClause() != null){
1780            this.getIntoTableClause().acceptChildren(v);
1781        }
1782
1783        if (this.getDistributeBy() != null){
1784            this.getDistributeBy().acceptChildren(v);
1785        }
1786
1787        if (this.getIsolationClause() != null){
1788            this.getIsolationClause().acceptChildren(v);
1789        }
1790
1791        if (this.getOptionClause() != null){
1792            this.getOptionClause().acceptChildren(v);
1793        }
1794
1795        if (this.getOffsetClause() != null){
1796            this.getOffsetClause().acceptChildren(v);
1797        }
1798
1799        if (this.getFetchFirstClause() != null){
1800            this.getFetchFirstClause().acceptChildren(v);
1801        }
1802
1803        if (this.getTimeTravel() != null){
1804            this.getTimeTravel().acceptChildren(v);
1805        }
1806
1807        if (this.getHintClause() != null){
1808            this.getHintClause().acceptChildren(v);
1809        }
1810
1811        v.postVisit(this);
1812        return ;
1813
1814    };
1815
1816    /**
1817     *  Add an order by clause to this class.
1818     * @param orderByStr new order by string
1819     * @return added order by clause.
1820     */
1821    public  TOrderBy addOrderBy(String orderByStr){
1822        if (this.getOrderbyClause() != null){
1823            this.getOrderbyClause().addOrderByItem(orderByStr);
1824        }else{
1825
1826            TOrderBy orderBy = new TOrderBy();
1827            orderBy.setGsqlparser(this.getGsqlparser());
1828            orderBy.setString(" order by "+orderByStr);
1829            this.orderbyClause = orderBy;
1830            TSourceToken last_token = null;
1831            if (this.getGroupByClause() != null){
1832                last_token = this.getGroupByClause().getEndToken();
1833            }else if (this.getWhereClause() != null){
1834                last_token = this.getWhereClause().getEndToken();
1835            }else{
1836                last_token = joins.getEndToken();
1837            }
1838
1839            orderbyClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1);
1840
1841           for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){
1842               TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i);
1843               if (node instanceof TSelectSqlStatement)
1844               {
1845                   // change all end token of parse tree node except the last order by item
1846                   node.setEndToken(orderbyClause.getEndToken());
1847               }
1848           }
1849        }
1850
1851        return this.getOrderbyClause();
1852    }
1853
1854    /**
1855     *  this function is alias of addWhereClause
1856     * @param condition new condition
1857     * @return new where clause
1858     */
1859    public TWhereClause addCondition(String condition){
1860        return  addWhereClause(condition);
1861    }
1862
1863    public TWhereClause addConditionOR(String condition){
1864        return  addWhereClauseOR(condition);
1865    }
1866
1867    public  TWhereClause addWhereClause(String condition){
1868       return doAddWhereClause(condition,true);
1869    }
1870
1871    public  TWhereClause addWhereClauseOR(String condition){
1872       return doAddWhereClause(condition,false);
1873    }
1874
1875    protected  TWhereClause doAddWhereClause(String condition, boolean isAnd){
1876
1877        if (this.getWhereClause() != null){
1878                if (isAnd){
1879                    this.getWhereClause().getCondition().addANDCondition(condition);
1880                }else{
1881                    this.getWhereClause().getCondition().addORCondition(condition);
1882                }
1883
1884          }else{
1885             TWhereClause whereClause = new TWhereClause();
1886             whereClause.setGsqlparser(this.getGsqlparser());
1887             whereClause.setString(" where "+condition);
1888             this.setWhereClause(whereClause);
1889
1890            TSourceToken last_token = null;
1891            TJoin lastjoin = joins.getJoin(joins.size()-1);
1892            if (lastjoin.getJoinItems().size() > 0){
1893                TJoinItem lastitem = lastjoin.getJoinItems().getJoinItem(lastjoin.getJoinItems().size()-1);
1894                 last_token = lastitem.getEndToken();
1895            }else {
1896                last_token = joins.getEndToken();
1897            }
1898
1899             whereClause.addAllMyTokensToTokenList(last_token.container, last_token.posinlist+1);
1900
1901            for(int i=0;i<last_token.getNodesEndWithThisToken().size();i++){
1902                TParseTreeNode node = last_token.getNodesEndWithThisToken().get(i);
1903                if (!((node instanceof TJoinList)
1904                        ||(node instanceof TJoin)
1905                        ||(node instanceof TJoinItemList)
1906                        ||(node instanceof TJoinItem)
1907                        ))
1908                {
1909                    // change all end token of parse tree node except the last order by item
1910                    node.setEndToken(whereClause.getEndToken());
1911                }
1912            }
1913
1914          }
1915           return this.getWhereClause();
1916    }
1917
1918    private ArrayList<String> columnsInFromClause = null;
1919
1920
1921    @Override
1922    public TFromClause getFromClause() {
1923        // #todo , select union 类型的 sql 语句,需要穿透到低层的各个 子 select 语句,需要进一步完善
1924        TFromClause ret = super.getFromClause();
1925        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1926            return   this.getRightStmt().getFromClause();
1927        }else{
1928            return  ret;
1929        }
1930    }
1931
1932    public TResultColumnList getResultColumnList(boolean useColumnsFromLeftmost) {
1933        TResultColumnList ret = super.getResultColumnList();
1934        if (ret != null) return ret;
1935
1936        if (isCombinedQuery()){
1937            if (useColumnsFromLeftmost) {
1938                return this.getFarLeftStmt().getResultColumnList();
1939            } else {
1940                return   this.getRightStmt().getResultColumnList();
1941            }
1942        }
1943        return ret;
1944
1945
1946//        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1947//            return   this.getRightStmt().getResultColumnList();
1948//        }else{
1949//            return  ret;
1950//        }
1951    }
1952
1953    @Override
1954    public TResultColumnList getResultColumnList() {
1955        return getResultColumnList(false);
1956
1957//        TResultColumnList ret = super.getResultColumnList();
1958//        if ((ret == null)&&(isCombinedQuery()&&(this.getRightStmt()!=null))){
1959//            return   this.getRightStmt().getResultColumnList();
1960//        }else{
1961//            return  ret;
1962//        }
1963    }
1964
1965    public ArrayList<String> getColumnsInFromClause() {
1966        if (columnsInFromClause != null) return columnsInFromClause;
1967        columnsInFromClause = new ArrayList<String>();
1968        TTable lcTable;
1969        for(int j=0;j<tables.size();j++){
1970            lcTable = tables.getTable(j);
1971            switch (lcTable.getTableType()){
1972                case objectname:
1973                    break;
1974                case subquery:
1975                    TSelectSqlStatement subQuery = lcTable.getSubquery();
1976                                        if (subQuery.getResultColumnList() != null)
1977                                                for(int i=0;i<subQuery.getResultColumnList().size();i++){
1978                                                        TResultColumn resultColumn = subQuery.getResultColumnList().getResultColumn(i);
1979                                                        String aliasName = null;
1980                                                        if (resultColumn.getAliasClause() != null){
1981                                                                aliasName = resultColumn.getAliasClause().getAliasName().toString();
1982                                                        }else{
1983                                                                if (resultColumn.getExpr().getObjectOperand() != null){
1984                                                                        aliasName = resultColumn.getExpr().getObjectOperand().toString();
1985                                                                }
1986                                                        }
1987                                                        if (aliasName != null){
1988                                                                columnsInFromClause.add(TSQLEnv.getObjectName(aliasName));
1989                                                        }
1990                                                }
1991                    break;
1992            }
1993        }
1994        return columnsInFromClause;
1995    }
1996
1997    public void addColumnInSelectListToSQLEnv(TSQLTable sqlTable){
1998
1999        if (sqlTable == null) return;
2000        if (this.getValueClause() != null) return;
2001                
2002                if (this.getResultColumnList() != null)
2003                        for(int i=0;i<this.getResultColumnList().size();i++){
2004                                TResultColumn resultColumn = this.getResultColumnList().getResultColumn(i);
2005                                String aliasName = null;
2006                                if (resultColumn.getAliasClause() != null){
2007                                        aliasName = resultColumn.getAliasClause().getAliasName().toString();
2008                                }else{
2009                                        if (resultColumn.getExpr().getObjectOperand() != null){
2010                                                aliasName = resultColumn.getExpr().getObjectOperand().toString();
2011                                        }
2012                                }
2013                                if (aliasName != null){
2014                                        sqlTable.addColumn(TSQLEnv.getObjectName(aliasName));
2015                                }
2016                        }
2017    }
2018
2019    /**
2020     * search column in the select list
2021     *
2022     * Internal function, DON'T call it explicitly.
2023     * @param pColumn
2024     * @param pMustIn
2025     * @return true if found.
2026     */
2027    public boolean searchColumnInResultSet(TObjectName pColumn,boolean pMustIn){
2028        boolean lcResult = false;
2029        int candidateTableCnt = 0;
2030        int numOfColumnStar = 0;
2031        TResultColumn columnStar = null;
2032
2033
2034
2035        TResultColumn c = null;
2036        String lookupKey = IdentifierService.normalizeStatic(this.dbvendor, ESQLDataObjectType.dotColumn,pColumn.getColumnNameOnly());
2037        if ( (lookupKey != null) && (c=  this.getExpandedResultColumns().get(lookupKey)) != null)
2038        {
2039            //System.out.println("Found:"+pColumn.toString());
2040            pColumn.setSourceColumn(c);
2041            c.getTargetColumns().addObjectName(pColumn);
2042
2043            return true;
2044        }else{
2045           // System.out.println("NotCatch:"+pColumn.toString());
2046        }
2047
2048        if (isCombinedQuery()){
2049            boolean lcResult1;//,lcResult2;
2050            // search column in all select
2051            lcResult1 = getFarLeftStmt().searchColumnInResultSet(pColumn,pMustIn);
2052            if (!lcResult1)
2053            lcResult1 = rightStmt.searchColumnInResultSet(pColumn,pMustIn);
2054            return  lcResult1;
2055        }
2056
2057        if (getResultColumnList() == null) return  false;
2058
2059        if (pColumn.toString().endsWith("*")){
2060            // pColumn here is o1.*
2061            // select o1.*, o2.c1
2062            // from (select c123, c345 from some_table) o1, other_table o2
2063            pColumn.setColumnsLinkedToStar(this.getResultColumnList());
2064            return true;
2065        }
2066
2067        // search columns in select list, skip t.* but count it for later use
2068        for(int i=0;i<getResultColumnList().size();i++){
2069            TResultColumn lcField = getResultColumnList().getResultColumn(i);
2070            if (lcField.toString().endsWith("*")){
2071                numOfColumnStar++;
2072                columnStar = lcField;
2073                continue;
2074            }
2075            lcResult = lcField.isMatchedWithResultColumn(this.dbvendor, pColumn);
2076            if (lcResult){
2077                pColumn.setSourceColumn(lcField);
2078                lcField.getTargetColumns().addObjectName(pColumn);
2079                break;
2080            }
2081        }
2082
2083        if (lcResult) return true;
2084
2085//        // search in * column, including t.* and *
2086        for(int i=0;i<getResultColumnList().size();i++){
2087            TResultColumn lcField = getResultColumnList().getResultColumn(i);
2088            if (lcField.toString().endsWith("*")){
2089                // search column in t.*, have to check column in table t
2090                String prefixTableName = "";
2091                if (lcField.toString().endsWith(".*")){
2092                    String[] a = lcField.toString().split("[.]");
2093                    prefixTableName = a[a.length - 2];
2094                }
2095                for(int j=0;j<tables.size();j++){
2096                    lcResult = tables.getTable(j).searchColumn(this,prefixTableName,pColumn,false);
2097                    if (lcResult) {
2098//                        tables.getTable(j).getLinkedColumns().addObjectName(pColumn);
2099//                        pColumn.setSourceTable(tables.getTable(j));
2100                        pColumn.setSourceColumn(lcField);
2101                        lcField.getTargetColumns().addObjectName(pColumn);
2102                        break;
2103                    }
2104                }
2105            }else{
2106                continue;
2107            }
2108            if (lcResult) break;
2109        }
2110
2111        if (lcResult) return true;
2112
2113        if (pMustIn){
2114            if (tables.size() == 1){ // only a single table in from clause
2115                lcResult = true;
2116                boolean inStarColumn = false;
2117//                tables.getTable(0).getLinkedColumns().addObjectName(pColumn);
2118//                pColumn.setSourceTable(tables.getTable(0));
2119                for(int i=0;i<getResultColumnList().size();i++) {
2120                    TResultColumn lcField = getResultColumnList().getResultColumn(i);
2121                    if (lcField.toString().endsWith("*")) {
2122                        String prefixTableName = "";
2123                        if (lcField.toString().endsWith(".*")){
2124                            String[] a = lcField.toString().split("[.]");
2125                            prefixTableName = a[a.length - 2];
2126                        }
2127                        tables.getTable(0).searchColumn(this,prefixTableName,pColumn,true);
2128                        pColumn.setSourceColumn(lcField);
2129                        lcField.getTargetColumns().addObjectName(pColumn);
2130                        inStarColumn = true;
2131                        break;
2132                    }
2133                }
2134                if (!inStarColumn){
2135
2136                    if (!locateVariableOrParameter(pColumn)){
2137                        // check variable before raise error
2138
2139                        // raise
2140                        TSyntaxError err = new TSyntaxError(pColumn.getStartToken().toString()
2141                                ,pColumn.getStartToken().lineNo,pColumn.getStartToken().columnNo
2142                                ,String.format("Column %s is not found in subquery",pColumn.toString())
2143                                ,EErrorType.sphint ,TBaseType.MSG_ERROR_COLUMN_NOT_FOUND,this,pColumn.getStartToken().posinlist);
2144                        this.parseerrormessagehandle( err);
2145                    }
2146
2147                }
2148            }else if (numOfColumnStar == 1){// only a single * column in select list, but more than one table in from clause
2149
2150                pColumn.setSourceColumn(columnStar);
2151                columnStar.getTargetColumns().addObjectName(pColumn);
2152                if (columnStar.toString().endsWith(".*")){
2153                    lcResult = true;
2154                    String[] a = columnStar.toString().split("[.]");
2155                    String prefixTableName = a[a.length - 2];
2156                    for(int i=0;i<tables.size();i++){
2157                        if (tables.getTable(i).checkTableByName(prefixTableName)){
2158                            tables.getTable(i).searchColumn(this,prefixTableName,pColumn,true);
2159//                            tables.getTable(i).getLinkedColumns().addObjectName(pColumn);
2160//                            pColumn.setSourceTable(tables.getTable(i));
2161                            pColumn.setSourceColumn(columnStar);
2162                            columnStar.getTargetColumns().addObjectName(pColumn);
2163                            break;
2164                        }
2165                    }
2166                }else{
2167                    lcResult = false;
2168                    // * column, no table prefix, this column can only be in one of tables
2169                    for(int i=0;i<tables.size();i++){
2170                        lcResult = tables.getTable(i).searchColumn(this,"",pColumn,false);
2171                        //tables.getTable(i).getLinkedColumns().addObjectName(pColumn);
2172                        //pColumn.setSourceTable(tables.getTable(i));
2173                        pColumn.setSourceColumn(columnStar);
2174                        columnStar.getTargetColumns().addObjectName(pColumn);
2175                    }
2176                }
2177                if (!lcResult) {
2178                    lcResult = linkToFirstTable(pColumn,0);
2179                }
2180            }else{
2181                // multi tables in from clause and multi * column in select list.
2182                lcResult = linkToFirstTable(pColumn,0);
2183            }
2184        }
2185
2186        return lcResult;
2187
2188        //if (lcResult) return true;
2189
2190        // From now on, let's search in * column, there maybe more than one * column in the select list, such as t1.*, t2.*
2191//        TResultColumn resultColumn = getResultColumnList().getResultColumn(0);
2192//        if ((getResultColumnList().size() == 1) &&(resultColumn.toString().equalsIgnoreCase("*") )){
2193//            // search in * or t1.* in the select list
2194//            int tableCntInFromClause = 0;
2195//            TTable tableInFromClause = null;
2196//            for(int i=0;i<tables.size();i++){
2197//                TTable tn = tables.getTable(i);
2198//                if (tn.getEffectType() == ETableEffectType.tetTeradataReference) continue;
2199//                tableInFromClause = tn;
2200//                tableCntInFromClause++;
2201//            }
2202//            //if (tables.size() == 1){
2203//            if (tableCntInFromClause == 1){
2204//                    //TTable t0 = tables.getTable(0);
2205//                TTable t0 = tableInFromClause;
2206//
2207//                if (t0.isBaseTable()){
2208//                        lcResult = fireOnMetaDatabaseTableColumn(t0.getPrefixServer(),t0.getPrefixDatabase(),t0.getPrefixSchema(),t0.getName(),pColumn.getColumnNameOnly());
2209//                        if (! lcResult) candidateTableCnt++;
2210//                    }else{
2211//                        if (t0.getTableType() == ETableSource.subquery){
2212//                            if (t0.isIncludeColumnAlias()){
2213//                                lcResult = t0.searchColumnInAlias(pColumn);
2214//                            }else{
2215//                                lcResult = t0.getSubquery().searchColumnInResultSet(pColumn,pMustIn);
2216//                                if (! lcResult) candidateTableCnt++;
2217//                            }
2218//                        }else if (t0.isCTEName()){
2219//                            lcResult = t0.getCTE().searchColumnInResultSet(this,t0,pColumn,pMustIn);
2220//                            if (! lcResult) candidateTableCnt++;
2221//                        }
2222//                    }
2223//                    if (pMustIn) lcResult = true;
2224//                    if (lcResult){
2225//                        t0.getLinkedColumns().addObjectName(pColumn);
2226//                        pColumn.setSourceTable(t0);
2227//                        pColumn.setSourceColumn(resultColumn);
2228//                        resultColumn.getTargetColumns().addObjectName(pColumn);
2229//                    }
2230//            }else{ // more than one table
2231//                    candidateTableCnt = 0;
2232//                    for(int i=0;i<tables.size();i++){
2233//                        TTable tn = tables.getTable(i);
2234//                        if (tn.isBaseTable()){
2235//                            lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly());
2236//                            if (!lcResult) candidateTableCnt++;
2237//                        }else{
2238//                            if (tn.getTableType() == ETableSource.subquery){
2239//                                if (tn.isIncludeColumnAlias()){
2240//                                    lcResult = tn.searchColumnInAlias(pColumn);
2241//                                }else{
2242//                                    lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,false);
2243//                                    if (!lcResult) candidateTableCnt++;
2244//                                }
2245//                            }else if (tn.isCTEName()){
2246//                                lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,false);
2247//                                if (!lcResult) candidateTableCnt++;
2248//                            }
2249//                        }
2250//
2251//                        if (lcResult){
2252//                            tn.getLinkedColumns().addObjectName(pColumn);
2253//                            pColumn.setSourceTable(tn);
2254//                            pColumn.setSourceColumn(resultColumn);
2255//                            resultColumn.getTargetColumns().addObjectName(pColumn);
2256//                            break;
2257//                        }
2258//                    }
2259//                    if ((!lcResult) && (pMustIn)) linkToFirstTable(pColumn,candidateTableCnt);
2260//            }
2261//           // }
2262//        }
2263//
2264//        if (lcResult) return true;
2265//
2266//        // search t.*
2267//        //int starColumnPos = 0,
2268//        int numOfTableDotStar=0;
2269//        for (int i=0;i<getResultColumnList().size();i++){
2270//            if (getResultColumnList().getResultColumn(i).toString().endsWith(".*")){
2271//                numOfTableDotStar++;
2272//            }
2273//        }
2274//
2275//        TResultColumn rc = null;
2276//        TTable tn = null;
2277//        for (int i=0;i<getResultColumnList().size();i++){
2278//            if (!getResultColumnList().getResultColumn(i).toString().endsWith(".*")) continue;
2279//            rc = getResultColumnList().getResultColumn(i);
2280//          //  starColumnPos = i;
2281//
2282//            for (int j=0;j<tables.size();j++){
2283//                if (! tables.getTable(j).equalByName(rc.getPrefixTable())) continue;
2284//                tn = tables.getTable(j);
2285//
2286//                if (tn.isBaseTable()){
2287//                    lcResult = fireOnMetaDatabaseTableColumn(tn.getPrefixServer(),tn.getPrefixDatabase(),tn.getPrefixSchema(),tn.getName(),pColumn.getColumnNameOnly());
2288//                    if (!lcResult) candidateTableCnt++;
2289//                }else{
2290//                    if (tn.getTableType() == ETableSource.subquery){
2291//                        if (tn.isIncludeColumnAlias()){
2292//                            lcResult = tn.searchColumnInAlias(pColumn);
2293//                        }else{
2294//                            lcResult = tn.getSubquery().searchColumnInResultSet(pColumn,((pMustIn)&&(numOfTableDotStar == 1)));
2295//                            if (!lcResult) candidateTableCnt++;
2296//                        }
2297//                    }else if (tn.isCTEName()){
2298//                        lcResult = tn.getCTE().searchColumnInResultSet(this,tn,pColumn,((pMustIn)&&(numOfTableDotStar == 1)));
2299//                        if (!lcResult) candidateTableCnt++;
2300//                    }
2301//                }
2302//
2303//                if (lcResult){
2304//                    tn.getLinkedColumns().addObjectName(pColumn);
2305//                    pColumn.setSourceTable(tn);
2306//                    pColumn.setSourceColumn(rc);
2307//                    rc.getTargetColumns().addObjectName(pColumn);
2308//                    break;
2309//                }
2310//            }
2311//            if (lcResult) break;
2312//        }
2313//
2314//        if (lcResult) return true;
2315//
2316//        if ((pMustIn) && (numOfTableDotStar == 1) && (tn != null)){
2317//            tn.getLinkedColumns().addObjectName(pColumn);
2318//            pColumn.setSourceTable(tn);
2319//            pColumn.setSourceColumn(rc);
2320//            rc.getTargetColumns().addObjectName(pColumn);
2321//            lcResult = true;
2322//        }
2323//
2324//        if (lcResult) return true;
2325//
2326//        if ((pMustIn) && (numOfTableDotStar > 0)) lcResult = linkToFirstTable(pColumn,candidateTableCnt);
2327//
2328//        if ((pMustIn)&&(!lcResult)) try {
2329//            throw new Exception(" column must be found in the select list:"+pColumn.toString());
2330//        } catch (Exception e) {
2331//            e.printStackTrace();
2332//        }
2333//
2334//        return lcResult;
2335    }
2336
2337
2338}