001package gudusoft.gsqlparser.nodes;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.compiler.TStmtScope;
005import gudusoft.gsqlparser.nodes.hive.THiveKeyValueProperty;
006import gudusoft.gsqlparser.nodes.mssql.TForXMLClause;
007import gudusoft.gsqlparser.nodes.snowflake.TAtBeforeClause;
008import gudusoft.gsqlparser.nodes.snowflake.TStageReference;
009import gudusoft.gsqlparser.nodes.teradata.THashByClause;
010import gudusoft.gsqlparser.nodes.teradata.TTDUnpivot;
011import gudusoft.gsqlparser.resolver.TResolverHelpUtils;
012import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType;
013import gudusoft.gsqlparser.sqlenv.TSQLEnv;
014import gudusoft.gsqlparser.sqlenv.TSQLTable;
015import gudusoft.gsqlparser.util.SQLUtil;
016import gudusoft.gsqlparser.stmt.TMergeSqlStatement;
017import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
018import gudusoft.gsqlparser.stmt.hive.THiveFromQuery;
019
020import java.util.ArrayList;
021
022/**
023 * Represents various kinds of table source in from clause. Can also be a simple table/view name in create table and all other places.
024 * result of {@link #getTableType} can be one of:
025 *<ul>
026 * <li>ftt_objectname, in from clause, a simple table/view name, reference: {@link TTable#tableName}<li>
027 * <li>ftt_subquery, is a subquery that retrieves rows from the database, also known as derived table. reference: {@link TTable#subquery}</li>
028 * <li>ftt_tableExpr,it's usually a table-valued expression., reference: {@link TTable#tableExpr}</li>
029 * <li>ftt_function, it's usually a table-valued function., reference: {@link TTable#funcCall}</li>
030 * <li>{@link ETableSource#rowList}, it's constructed rows, reference: {@link TTable#rowList}</li>
031 * <li>ftt_containsTable, CONTAINSTABLE clause of sql server. reference: {@link TTable#containsTable}, type of {@link TContainsTable}</li>
032 * <li>ftt_freetextTable, FREETEXTTABLE  clause of sql server. reference: {@link TTable#containsTable}, type of {@link TContainsTable}</li>
033 * <li>ftt_openrowset, OPENROWSET clause of sql server. reference: {@link TTable#openRowSet}, type of {@link TOpenRowSet}</li>
034 * <li>ftt_openxml, OPENXML clause of sql server. reference: {@link TTable#openXML}, type of {@link TOpenXML }</li>
035 * <li>ftt_opendatasource, OPENDATASOURCE clause of sql server. reference: {@link TTable#openDatasource}, type of {@link TOpenDatasource}</li>
036 * <li>ftt_openquery, OPENQUERY clause of sql server. reference: {@link TTable#openquery}, type of (@link TOpenQuery)</li>
037 * </ul>
038 *
039 *
040*/
041
042public class TTable extends TNodeWithAliasClause implements IRelation {
043    private ArrayList<TAttributeNode> relationAttributes;
044
045    /**
046     * @deprecated ,  this method is deprecated since version 3.3.1.0, don't use it in TSQLResolver2
047     * @return
048     */
049    @Override
050    public ArrayList<TAttributeNode> getAttributes(){
051        if (relationAttributes == null) {
052            relationAttributes = new ArrayList<>();
053        }
054        return relationAttributes;
055    }
056
057    @Override
058    public String getRelationName(){
059        return this.getName();
060    }
061
062    @Override
063    public int size(){
064        return relationAttributes != null ? relationAttributes.size() : 0;
065    }
066
067    public void setStageReference(TStageReference stageReference) {
068        this.stageReference = stageReference;
069    }
070
071    private TStageReference stageReference;
072
073    public TStageReference getStageReference() {
074        return stageReference;
075    }
076    private TAtBeforeClause timeTravelClause;
077
078    public void setTimeTravelClause(TAtBeforeClause timeTravelClause) {
079        this.timeTravelClause = timeTravelClause;
080    }
081
082    public TAtBeforeClause getTimeTravelClause() {
083        return timeTravelClause;
084    }
085
086    private TCaseJoinClause caseJoin;
087
088    public void setCaseJoin(TCaseJoinClause caseJoin) {
089        this.caseJoin = caseJoin;
090    }
091
092    public TCaseJoinClause getCaseJoin() {
093        return caseJoin;
094    }
095
096    public String getStageName(){
097        if (this.getTableName() == null) return null;
098        if (this.getTableName().getDbObjectType() != EDbObjectType.stage) return null;
099        return this.getTableName().getObjectString();
100    }
101    public final static String PIVOT_CLAUSE_ALIAS = "(pivot_table)";
102    public final static String UNPIVOT_CLAUSE_ALIAS = "(unpivot_table)";
103    public final static String TABLE_COLLECTION_ALIAS = "(table_collection)";
104
105
106    boolean isAttributesInitialized = false;
107
108    /**
109     * Initialize a star attribute node (tableName.*) for this table.
110     * This is used for regular tables (without DDL/metadata) in contexts where
111     * they need to compete with subqueries that have star columns.
112     * For example, in MERGE statements, the target table needs a star attribute
113     * so that unqualified columns in the ON clause can be resolved to it
114     * instead of being incorrectly pushed down through the source subquery's star column.
115     */
116    public void initStarAttribute(){
117        if (isAttributesInitialized) return;
118        TAttributeNode.addNodeToList(new TAttributeNode( getDisplayName()+".*",this),getAttributes());
119        isAttributesInitialized = true;
120    }
121
122    public void initAttributeForXMLTable(){
123       // if (isAttributesInitialized) return;
124            //relationAttributes.add(new TAttributeNode( getDisplayName()+".*",this));
125        TAttributeNode.addNodeToList(new TAttributeNode( getDisplayName()+".*",this),getAttributes());
126        isAttributesInitialized = true;
127    }
128
129    public void initAttributeForTableFunction(){
130       // if (isAttributesInitialized) return;
131           //relationAttributes.add( new TAttributeNode( getDisplayName()+".value",this));
132        TAttributeNode.addNodeToList(new TAttributeNode( getDisplayName()+".value",this),getAttributes());
133        if (this.getName().equals("STRING_SPLIT")){ 
134            // TRING_SPLIT函数生成的表只有两个字段:value和可选的ordinal
135            TAttributeNode.addNodeToList(new TAttributeNode( getDisplayName()+".ordinal",this),getAttributes());
136        }
137        isAttributesInitialized = true;
138    }
139
140    public void initAttributeForRowList(){
141       // if (isAttributesInitialized) return;
142       // relationAttributes.add( new TAttributeNode( getDisplayName()+".value",this));
143        if (getValueClause() == null) return;
144        if (getValueClause().getRows().size() == 0) return;
145
146        int i = 0;
147        String columnName = "";
148        TObjectNameList aliasColumnNameList = null;
149        // 1. 如果有 table alias 中指定 column, 遍历alias column
150        // 2. 如果 table alias 没有指定column, 遍历 subquery or  values() 中的 resultcolumn
151        // 如果遍历alias column,可能存在 alias column 中column 数量和  subquery or  values() 中的 resultcolumn 中不等的现象
152        // 例如 subquery or  values() 中的 resultcolumn 中为 * column,
153        // 或者 snowflake 中的 pivot clause.(c:\prg\gsp_sqlfiles\TestCases\private\dataflow\snowflake\pivot_clause_1.sql)
154
155        TAliasClause aliasClause = this.getAliasClause();
156        if (aliasClause != null){
157            aliasColumnNameList = aliasClause.getColumns();
158        }
159        for(TResultColumn resultColumn:getValueClause().getRows().get(0)){
160            columnName = resultColumn.getDisplayName();
161            if ((aliasColumnNameList != null)&&(aliasColumnNameList.size()>i)){
162                columnName = aliasColumnNameList.getObjectName(i).getColumnNameOnly();
163            }
164            TAttributeNode newNode = new TAttributeNode(this.getDisplayName() + "." + columnName, this, resultColumn);
165            //newNode.setAttributeCreatedFromAliasColumn(true);
166            //relationAttributes.add(newNode);
167            TAttributeNode.addNodeToList(newNode,relationAttributes);
168            i++;
169        }
170
171        TBaseType.log(String.format("Prepare attributes (num = %d) for rowList (values) : <%s>",this.getAttributes().size() ,this.getDisplayName()),TLog.DEBUG,this.getTableName());
172        int c = 0;
173        for(TAttributeNode node: this.getAttributes()){
174            TBaseType.log(String.format("\tAttribute: <%s>, result column: <%s>",node.getName(), node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG);
175            c++;
176            if (c > TLog.OUTPUT_ATTRIBUTES_MAX){
177                TBaseType.log(String.format("\t...skipped after output %d attributes",c-1),TLog.DEBUG,this.getTableName().getStartToken());
178                break;
179            }
180        }
181
182
183        isAttributesInitialized = true;
184    }
185
186
187    public void initAttributesFromCTE(TCTE cte){
188       // if (isAttributesInitialized) return;
189
190        for (TAttributeNode node1 : cte.getAttributes()) {
191            TAttributeNode newNode = new TAttributeNode(this.getDisplayName() + "." + node1.getLastPartOfName(), this, node1.getSqlColumn(), node1.getSubLevelResultColumn());
192            if (node1.getAccompaniedAttributeNodes().size() > 0){
193                for(TAttributeNode n:node1.getAccompaniedAttributeNodes()){
194                    newNode.getAccompaniedAttributeNodes().add(n);
195                }
196            }
197            //relationAttributes.add(newNode);
198            TAttributeNode.addNodeToList(newNode,relationAttributes);
199        }
200
201        TBaseType.log(String.format("Prepare attributes (num = %d) for cte ref: <%s>",this.getAttributes().size() ,this.getTableName().toString()),TLog.DEBUG,this.getTableName());
202        int c = 0;
203        for(TAttributeNode node: this.getAttributes()){
204            if (node.getSqlColumn() != null){
205                TBaseType.log(String.format("\tAttribute: <%s>, SQL column: <%s>",node.getName(), node.getSqlColumn()!=null?node.getSqlColumn().toString():"N/A" ),TLog.DEBUG);
206            }else{
207                TBaseType.log(String.format("\tAttribute: <%s>, Select list column: <%s>",node.getName(), node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG);
208            }
209            c++;
210            if (c > TLog.OUTPUT_ATTRIBUTES_MAX){
211                TBaseType.log(String.format("\t...skipped after output %d attributes",c-1),TLog.DEBUG,this.getTableName().getStartToken());
212                break;
213            }
214        }
215
216        isAttributesInitialized = true;
217    }
218    public void  initAttributesFromSubquery(TSelectSqlStatement subquery, String prefix){
219        // TODO, not thread safe?
220      //  if ((isAttributesInitialized) && (!relationAttributes.isEmpty())) return;
221        if (subquery.getResultColumnList() == null) return;
222        int i = 0;
223        if (subquery.getResultColumnList() != null) {
224            TResultColumnList resultColumnListFromSubQuery = subquery.getResultColumnList(true);
225            for(TResultColumn column: resultColumnListFromSubQuery){
226                if (column.getAliasNameList().size() > 0){
227                    // 如果 column 有 alias name list, 则遍历 alias name list, 并把每个 alias name 作为 attribute node 添加到 relationAttributes 中
228                    // as (b1, b2, b3, b4, b5)
229                    // select t.a1, t.a2, stack(2, 'T', t.a1, t.a2, t.a3/t.a4, t.a5/t.a6,   'T+0', t.a7, t.a8, t.a9/t.a10, t.a11/t.a12) as (b1, b2, b3, b4, b5)  from db1.table1 t
230
231                    for(TObjectName aliasName: column.getAliasNameList()){
232                        this.addAttribute(new TAttributeNode(prefix + TBaseType.removeQuoteChar(aliasName.toString()),this,column,i));
233                        i++;
234                    }
235                }else {
236                    if (column.getDisplayName().endsWith("*")){
237                        TObjectName objectName = column.getExpr().getObjectOperand();
238                        if (objectName.getAttributeNodesDerivedFromFromClause().size() > 0){
239                            for(TAttributeNode attributeNode:objectName.getAttributeNodesDerivedFromFromClause()){
240                                //relationAttributes.add(new TAttributeNode( prefix + attributeNode.getLastPartOfName() ,this, attributeNode.getSqlColumn(), column,i));
241                                this.addAttribute(new TAttributeNode( prefix + attributeNode.getLastPartOfName() ,this, attributeNode.getSqlColumn(), column,i));
242                            }
243                        }else{
244                            // no attribute node derived from from clause, add the object name directly
245                            //relationAttributes.add(new TAttributeNode(prefix +"*",this,column,i));
246                            this.addAttribute(new TAttributeNode(prefix +"*",this,column,i));
247                        }
248                    }else{
249                        //relationAttributes.add(new TAttributeNode(prefix +column.getDisplayName(),this,column,i));
250                        this.addAttribute(new TAttributeNode(prefix +column.getDisplayName(),this,column,i));
251                    }
252                    i++;
253                }
254            }
255        }
256
257        //  如果 subQuery 是 combined query, 需要把所有 query 中的 select list 都加入进来。上面处理的仅仅为最右面的那个 subQuery
258        if (subquery.isCombinedQuery()){
259            TSelectSqlStatement left = subquery.getLeftStmt();
260            addNewAttributeFromSubQuery(left.getResultColumnList(true),getAttributes(),prefix);
261            while (left.isCombinedQuery()){
262                left = left.getLeftStmt();
263                addNewAttributeFromSubQuery(left.getResultColumnList(true),getAttributes(),prefix);
264            }
265        }
266        isAttributesInitialized = true;
267    }
268
269    void addNewAttributeFromSubQuery(TResultColumnList resultColumnList, ArrayList<TAttributeNode> attributeNodes, String prefix){
270        addNewAttributeFromSubQuery(resultColumnList,attributeNodes,prefix,null);
271    }
272
273    /**
274     * 当 subQuery 为 combined query 时,不仅仅把 right most 那个 subQuery 的 select list 作为 子查询的 attribute node list 添加上来
275     * 还需要把 其他 combined query 中的 subQuery 加入进来
276     *
277     *
278     *
279     * @param resultColumnList  subQuery 中的 select list
280     * @param attributeNodes  需要在该 attribute node 的 getAccompaniedAttributeNodes() 中添加新 node
281     * @param prefix  该前缀为 subQuery 的 alias,或 CTE 的 name 决定
282     * @param specifiedColumnList 当 table 为 CTE 时,并且 CTE 自己指定了 column list, 那么 attribute node 的 name 由该 column list 决定,
283     *                            而不是 subQuery 中的 select list 确定
284     *
285     */
286    void addNewAttributeFromSubQuery(TResultColumnList resultColumnList, ArrayList<TAttributeNode> attributeNodes, String prefix, TObjectNameList specifiedColumnList){
287        if (resultColumnList == null) return;
288        if (resultColumnList.size() !=  attributeNodes.size()){ 
289            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
290                TBaseType.log(String.format("When add attribute from subQuery, the size of select list and attributes is not the same: %d <> %d",resultColumnList.size(),attributeNodes.size())
291                        ,TLog.ERROR,resultColumnList.getStartToken());
292            }
293            return;
294        }
295        int i = 0;
296        for(TResultColumn column: resultColumnList){
297            TAttributeNode node = attributeNodes.get(i); // 根据 i 的值,找到原来对应位置的 attribute node,用来添加 accompanied node
298
299            if (column.getDisplayName().endsWith("*")){
300                TObjectName objectName = column.getExpr().getObjectOperand();
301                for(TAttributeNode attributeNode:objectName.getAttributeNodesDerivedFromFromClause()){
302                    if (specifiedColumnList == null){
303                        node.getAccompaniedAttributeNodes().add(new TAttributeNode( prefix + attributeNode.getLastPartOfName() ,this, attributeNode.getSqlColumn(), column,i));
304                    }else{
305                        TObjectName c = specifiedColumnList.getObjectName(i);
306                        node.getAccompaniedAttributeNodes().add(new TAttributeNode( prefix + c.toString() ,this, attributeNode.getSqlColumn(), column,i));
307                    }
308                }
309            }else{
310                if (specifiedColumnList == null){
311                    node.getAccompaniedAttributeNodes().add(new TAttributeNode(prefix +column.getDisplayName(),this,column,i));
312                }else{
313                    TObjectName c = specifiedColumnList.getObjectName(i);
314                    node.getAccompaniedAttributeNodes().add(new TAttributeNode(prefix + c.toString(),this,column,i));
315                }
316            }
317            i++;
318        }
319    }
320
321    public String getDisplayName(){
322        if (getAliasClause() != null) return getAliasName();
323        String ret = null;
324        switch (getTableType()){
325            case objectname:
326                ret = getFullName();
327                break;
328            case tableExpr:
329                ret = TTable.TABLE_COLLECTION_ALIAS;
330                break;
331            default:
332                ret = toString();
333                break;
334        }
335        return ret;
336    }
337
338    public String getDisplayName(boolean removeDBLink){
339        if (!removeDBLink) return getDisplayName();
340        if (dbvendor != EDbVendor.dbvoracle) return getDisplayName();
341        // DM_MINING.FATURA_ODEME_SEGMENTASYONU@dblinkx
342        String ret = getDisplayName();
343        int atIndex = ret.indexOf('@');
344        if (atIndex > 0){
345            ret = ret.substring(0,atIndex);
346        }
347        return ret;
348    }
349
350
351    /**
352     * 在 sql script 中,和该 relation 关联的 attribute。
353     * select a from t;
354     * attribute a 就是 relation t 的 referenceAttribute, 如果没有 metadata and ddl,
355     * relation t 的 relationAttributes 应该可以推断出包含 a, 但 t 是否还包含其他的 attribute 就无从得知。
356     */
357    ArrayList<TObjectName> referenceAttributes = new ArrayList<>();
358
359//    public ArrayList<TObjectName> getReferenceAttributes(){
360//        return null;
361//    }
362
363    public void initAttributesForPivotTable(){
364       // if (isAttributesInitialized) return;
365        TPivotClause pivotClause = this.getPivotedTable().getPivotClauseList().getElement(0);
366        if (pivotClause.getType() == TPivotClause.pivot){
367
368            // 先添加 pivot clause 中的 attribute,以防止 先处理 [p].[3] -> p.*, 而导致 [p].[3] -> [p].[3] 没能正确匹配
369
370            // SELECT [p].[ADDRESS_ID]
371            //                      ,[p].[3] AS ADDRESS_LINE3
372            //                      ,[p].[2] AS ADDRESS_LINE2
373            //                      ,[p].[1] AS ADDRESS_LINE1 FROM [ADDRESS_LINES_CTE]
374            //                          PIVOT(MAX(value) FOR id IN ([1],[2],[3])) p
375
376            //relationAttributes.addAll(pivotClause.getAttributes());
377            TAttributeNode.addAllNodesToList(pivotClause.getAttributes(),getAttributes());
378
379            TTable sourceTable = this.getPivotedTable().getRelations().get(0);
380            // 如果 pivot alias clause 不为空,整个table的 prefix 都用这个alias
381            //  否则使用当前table的display name
382            String prefix;
383            if (pivotClause.getAliasClause() != null){
384                prefix = pivotClause.getDisplayName();
385            }else{
386                prefix = sourceTable.getDisplayName();
387            }
388
389            for(TAttributeNode node: sourceTable.getAttributes()){
390                    //relationAttributes.add(new TAttributeNode(prefix+"."+ TBaseType.getLastPartOfQualifiedName(node.getName()),sourceTable,node.getSubLevelResultColumn()));
391                TAttributeNode.addNodeToList(new TAttributeNode(prefix+"."+ TBaseType.getLastPartOfQualifiedName(node.getName()),sourceTable,node.getSubLevelResultColumn()),getAttributes());
392            }
393
394
395        }
396
397        isAttributesInitialized = true;
398    }
399
400    /**
401     * 主要是在处理列级别的信息,
402     * 它的主要目的是确保 JOIN 操作后的表对象包含所有参与 JOIN 的表的列信息,这对于后续的查询处理(特别是列引用解析)是必要的。
403     */
404    public void initAttributesForJoin(){
405        //if (isAttributesInitialized) return;
406        //relationAttributes.addAll(getJoinExpr().getAttributes());
407        TAttributeNode.addAllNodesToList(getJoinExpr().getAttributes(),getAttributes());
408        isAttributesInitialized = true;
409    }
410
411    public void initAttributesForUnnest(TSQLEnv sqlEnv, TSelectSqlStatement select ){
412       // if (isAttributesInitialized) return;
413        if (this.getAliasClause() != null){
414            if (this.getAliasClause().getColumns() != null){
415                for(TObjectName pColumn:this.getAliasClause().getColumns()){
416                       //relationAttributes.add( new TAttributeNode( this.getDisplayName()+"."+pColumn.toString() ,this));
417                    TAttributeNode.addNodeToList(new TAttributeNode( this.getDisplayName()+"."+pColumn.toString() ,this),getAttributes());
418                }
419            }else if (this.getAliasClause().getAliasName() != null){
420//                       SELECT *
421//                               FROM UNNEST(['foo', 'bar', 'baz', 'qux', 'corge', 'garply', 'waldo', 'fred']) AS element
422//                       WITH OFFSET AS offset
423                // add element as column of unnest table.
424                if (this.getUnnestClause().getColumns() != null){
425                    //   UNCOVERED_MOVE_Stage1 AS
426                    //  (SELECT
427                    //     Instrument_Partition_Key ,
428                    //     Consolidation_Entity_Levels ,
429                    //     FOTC_UDF_calc_uncovered_roll_off(ARRAY_AGG(STRUCT<Partition_Key STRING , Order_Number INT64 , Movement_In_Short FLOAT64 , Short_Increase_Uncovered FLOAT64 , Short_Increase_Covered_CS FLOAT64 , Short_Increase_Covered_RR FLOAT64> (Instrument_Partition_Key , Order_Number , Movement_In_Short_Balance_LCY , Short_Increase_Uncovered , Maturing_CS_Covering_Short_Increase , Maturing_RR_Covering_Short_Increase)
430                    //                                                ORDER BY Order_Number)) AS result_uncovered_moves ,
431                    //     FOTC_UDF_calc_uncovered_roll_off(ARRAY_AGG(STRUCT<Partition_Key STRING , Order_Number INT64 , Movement_In_Short FLOAT64 , Short_Increase_Uncovered FLOAT64 , Short_Increase_Covered_CS FLOAT64 , Short_Increase_Covered_RR FLOAT64> (Instrument_Partition_Key , Order_Number , Movement_In_Short_Balance_LCY , Short_Increase_Uncovered_By_Settled_RR , Maturing_CS_Covering_Short_Increase , Maturing_Settled_RR_Covering_Short_Increase)
432                    //                                                ORDER BY Order_Number)) AS result_uncovered_by_settled_moves
433                    //   FROM SHORTS_COVERING_RR
434                    //   GROUP BY
435                    //     Instrument_Partition_Key ,
436                    //     Consolidation_Entity_Levels) ,
437                    //  UNCOVERED_MOVE AS
438                    //  (SELECT
439                    //     Consolidation_Entity_Levels ,
440                    //     X.* ,
441                    //     Y.uncovered_move AS Move_Uncovered_By_Settled_RR_Short ,
442                    //     Y.covered_cs_move AS Move_Covered_By_Settled_CS_Short ,
443                    //     Y.covered_rr_move AS Move_Covered_By_Settled_RR_Short
444                    //   FROM
445                    //     UNCOVERED_MOVE_Stage1 ,
446                    //     UNNEST(result_uncovered_moves) AS X
447                    //   JOIN UNNEST(result_uncovered_by_settled_moves) AS Y ON X.Partition_Key = Y.Partition_Key
448                    //   AND X.order_key= Y.order_key)
449
450                    // UNNEST(result_uncovered_moves) 中的 result_uncovered_moves 来自 ARRAY_AGG(),
451                    // 这时候因为还没有进行 column resolver,所以无法知道 result_uncovered_moves 到底包含哪些 column
452                    // 因为 UNNEST(result_uncovered_moves) AS X 指定了 X 作为 Alias, 因此增加 X.* 作为 attributeNode
453                    // 不会导致问题。
454
455                    ArrayList<String> tf = null;
456                    TObjectName objectName = this.getUnnestClause().getColumns().getObjectName(0);
457                    for(TTable table: select.getRelations()){
458                        if (TParseTreeNode.subNodeInNode(this,table)) break;
459                        for(TAttributeNode attributeNode:table.getAttributes()){
460                            int matchResult = TStmtScope.matchAttribute(objectName.toString(), attributeNode.getName(),0,select);
461                            if (matchResult == TBaseType.MATCH_COLUMN_RESULT_MATCHED ) {
462                                objectName.setSourceTableBySQLResolver(select,attributeNode,table);
463                                objectName.setSourceAttributeNode(attributeNode);
464                                break;
465                            }
466                        }
467                        if (objectName.getSourceAttributeNode() != null){
468                            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
469                                TBaseType.log(String.format("Unnest table from source column: <%s>, linked to attribute node: <%s>"
470                                        ,objectName.toString(),objectName.getSourceAttributeNode().getName()),TLog.DEBUG,objectName);
471                            }
472
473                            // unnest(column), 其中的 column 可能对应array, 或者是 struct
474                            // 找一下看看是否有 struct
475
476                             tf = TResolverHelpUtils.searchTypedStruct(sqlEnv, objectName.getSourceAttributeNode().getSubLevelResultColumn());
477                            break;
478                        }
479                    }
480                    if (tf != null){
481                        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
482                            TBaseType.log(String.format("Prepare attribute node for unnest %s",this.getDisplayName()),TLog.DEBUG,this.getStartToken());
483                        }
484                        for(String columnName:tf){
485                            TAttributeNode newNode = new TAttributeNode(String.format("%s.%s",this.getDisplayName(),columnName),this,objectName.getSourceAttributeNode().getSubLevelResultColumn());
486                            //relationAttributes.add(newNode);
487                            TAttributeNode.addNodeToList(newNode,relationAttributes);
488                            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
489                                TBaseType.log(String.format("\t attribute node from struct: %s.%s with source column: %s"
490                                            , this.getDisplayName(),columnName, objectName.getSourceAttributeNode().getSubLevelResultColumn()==null?"N/A":objectName.getSourceAttributeNode().getSubLevelResultColumn().toString() ),TLog.DEBUG,this.getStartToken());
491                            }
492                        }
493                    }else{
494                           //relationAttributes.add( new TAttributeNode( this.getDisplayName()+".*",this));
495                        TAttributeNode.addNodeToList(new TAttributeNode( this.getDisplayName()+".*",this),getAttributes());
496                    }
497
498                }else{
499                       //relationAttributes.add( new TAttributeNode( this.getDisplayName()+"."+this.getAliasClause().getAliasName().toString() ,this));
500                    TAttributeNode.addNodeToList(new TAttributeNode( this.getDisplayName()+"."+this.getAliasClause().getAliasName().toString() ,this),getAttributes());
501                }
502            }
503        }else{
504            //SELECT value FROM UNNEST(nested_attribute)
505            // #TODO, 未处理 UNNEST 中的 nested_attribute,  nested_attribute 一般是一个 struct,那么应该把 struct 中的 column 也加入进来
506            // 没有指定输出 column 的name,默认为 value
507               //relationAttributes.add( new TAttributeNode( this.getDisplayName()+"."+"value" ,this));
508            TAttributeNode.addNodeToList(new TAttributeNode( this.getDisplayName()+"."+"value" ,this),getAttributes());
509        }
510
511        for(int i=0;i<getAttributes().size();i++){
512            TAttributeNode node = getAttributes().get(i);
513            if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
514                TBaseType.log(String.format("Prepare attribute node <%d> for unnest %s: %s",i+1,this.getDisplayName(),node.getName()),TLog.DEBUG,this.getStartToken());
515            }
516        }
517
518        isAttributesInitialized = true;
519    }
520
521   
522
523
524//    private ArrayList<String> expandedAttributes = new ArrayList<>();
525//
526//    public ArrayList<String> getExpandedAttributes() {
527//        return expandedAttributes;
528//    }
529
530
531    public void addAttribute(TAttributeNode node) {
532        if (node == null) return;
533        
534        // 检查是否已存在同名节点
535        for (TAttributeNode existing : getAttributes()) {
536            if (existing.getName().equals(node.getName())) {
537                return;
538            }
539        }
540        
541        //relationAttributes.add(node);
542        TAttributeNode.addNodeToList(node,relationAttributes);
543    }
544
545    private ArrayList<TObjectName> attributesReferenceToThisRelation = new ArrayList<>();
546
547    public ArrayList<TObjectName> getAttributesReferenceToThisRelation() {
548        return attributesReferenceToThisRelation;
549    }
550
551//    public boolean resolveAttribute(TObjectName attribute){
552//        boolean result = false;
553//        if (attribute.isQualified()) {
554//            result = attribute.resolveWithThisTable(this);
555//            if (result) {
556//                attributesReferenceToThisRelation.add(attribute);
557//                attribute.setResolvedRelation(this);
558//            }
559//            return result;
560//        }
561//        if (this.getResolvedTable() != null){
562//            result = this.getResolvedTable().searchColumn(attribute.toString());
563//            if (result){
564//                attribute.setResolvedRelation(this);
565//                return result;
566//            }
567//        }
568//        return result;
569//    }
570
571    private TSQLTable resolvedTable = null;
572    private boolean isResolved = false;
573
574    public void setResolvedTable(TSQLTable resolvedTable) {
575        this.resolvedTable = resolvedTable;
576        isResolved = true;
577    }
578
579    public void setResolved(boolean resolved) {
580        isResolved = resolved;
581    }
582
583    public TSQLTable getResolvedTable() {
584        return resolvedTable;
585    }
586
587    public boolean isResolved() {
588        return isResolved;
589    }
590
591    private ArrayList<TObjectName> columnsFromSQLEnv;
592
593    public ArrayList<TObjectName> getColumnsFromSQLEnv(TSQLEnv sqlEnv) {
594        if (columnsFromSQLEnv == null){
595            columnsFromSQLEnv = new ArrayList<>();
596        }
597
598        ArrayList<String> columns = sqlEnv.getColumnsInTable(this.tableName.toString(),true);
599        if (columns == null) return null;
600
601        for(String s:columns){
602            TObjectName column = TObjectName.createObjectName(this.dbvendor, EDbObjectType.column,new TSourceToken(s));
603            columnsFromSQLEnv.add(column);
604        }
605
606        return columnsFromSQLEnv;
607    }
608
609    private TJoinExpr joinExpr;
610
611    public void setJoinExpr(TJoinExpr joinExpr) {
612        this.joinExpr = joinExpr;
613    }
614
615    public TJoinExpr getJoinExpr() {
616        return joinExpr;
617    }
618
619    /**
620     *  该 table 对应的 sqlenv 中的 table 定义,包含具体的字段信息,有字段名称、数据类型等。
621     *
622     */
623//    private TSQLTable sqlTable;
624//
625//    public void setSqlTable(TSQLTable sqlTable) {
626//        this.sqlTable = sqlTable;
627//    }
628//
629//    public TSQLTable getSqlTable() {
630//        return sqlTable;
631//    }
632
633
634
635    private TForXMLClause forXMLClause;
636
637    public void setForXMLClause(TForXMLClause forXMLClause) {
638        this.forXMLClause = forXMLClause;
639    }
640
641    /**
642     * SQL Server for xml clause
643     * @return SQL Server for xml clause
644     */
645    public TForXMLClause getForXMLClause() {
646        return forXMLClause;
647    }
648
649    private TColumnDefinitionList columnDefinitions;
650
651    public TColumnDefinitionList getColumnDefinitions() {
652        return columnDefinitions;
653    }
654
655    /**
656     * Teradata HASH BY clause for table functions.
657     */
658    private THashByClause hashByClause;
659
660    /**
661     * Gets the HASH BY clause for Teradata table functions.
662     *
663     * @return the HASH BY clause, or null if not specified
664     */
665    public THashByClause getHashByClause() {
666        return hashByClause;
667    }
668
669    /**
670     * Sets the HASH BY clause for Teradata table functions.
671     *
672     * @param hashByClause the HASH BY clause
673     */
674    public void setHashByClause(THashByClause hashByClause) {
675        this.hashByClause = hashByClause;
676    }
677
678    /**
679     * Teradata LOCAL ORDER BY clause for table functions.
680     */
681    private TOrderBy localOrderBy;
682
683    /**
684     * Gets the LOCAL ORDER BY clause for Teradata table functions.
685     *
686     * @return the LOCAL ORDER BY clause, or null if not specified
687     */
688    public TOrderBy getLocalOrderBy() {
689        return localOrderBy;
690    }
691
692    /**
693     * Sets the LOCAL ORDER BY clause for Teradata table functions.
694     *
695     * @param localOrderBy the LOCAL ORDER BY clause
696     */
697    public void setLocalOrderBy(TOrderBy localOrderBy) {
698        this.localOrderBy = localOrderBy;
699    }
700
701    private TSQLEnv sqlEnv;
702
703    public void setSqlEnv(TSQLEnv sqlEnv) {
704        this.sqlEnv = sqlEnv;
705    }
706
707    public TSQLEnv getSqlEnv() {
708        return sqlEnv;
709    }
710
711    private TValueClause valueClause;
712
713    public TValueClause getValueClause() {
714        return valueClause;
715    }
716
717    public void setValueClause(TValueClause valueClause) {
718        this.valueClause = valueClause;
719    }
720
721    private TTable sourceTableOfPivot;
722
723    public void setSourceTableOfPivot(TTable sourceTableOfPivot) {
724        this.sourceTableOfPivot = sourceTableOfPivot;
725    }
726
727    public TTable getSourceTableOfPivot() {
728        return sourceTableOfPivot;
729    }
730
731    private TJsonTable jsonTable;
732
733    public void setJsonTable(TJsonTable jsonTable) {
734        this.jsonTable = jsonTable;
735    }
736
737    public TJsonTable getJsonTable() {
738        return jsonTable;
739    }
740
741    public void  setPropertyFromObjectName(TObjectName objectName, ETableEffectType tableEffectType){
742        setStartToken(objectName.getStartToken());
743        setEndToken(objectName.getEndToken());
744        setGsqlparser(objectName.getGsqlparser());
745        setEffectType(tableEffectType);
746        setTableType(ETableSource.objectname);
747    }
748    private TTDUnpivot tdUnpivot;
749
750    public void setTdUnpivot(TTDUnpivot tdUnpivot) {
751        this.tdUnpivot = tdUnpivot;
752    }
753
754    public TTDUnpivot getTdUnpivot() {
755
756        return tdUnpivot;
757    }
758
759    private TUnnestClause unnestClause;
760
761    public void setUnnestClause(TUnnestClause unnestClause) {
762        this.unnestClause = unnestClause;
763    }
764
765    public TUnnestClause getUnnestClause() {
766
767        return unnestClause;
768    }
769    //select b.TemaTakipNo, b.SevkID, db.FromDepo, db.ToDepo, d.UrunID UrunID1, r.UrunID2, d.Miktar AsortiMiktar, r.Miktar ReceteMiktar
770    //into #tmpIrsaliye
771    /**
772     * list of columns in select list, used as metadata to determine whether a column belong to this temp table in TCustomSqlStatement.linkColumnToTable
773     */
774    private TResultColumnList columnListInTempTable;
775
776    public void setColumnListInTempTable(TResultColumnList columnListInTempTable) {
777        this.columnListInTempTable = columnListInTempTable;
778    }
779
780    public TResultColumnList getColumnListInTempTable() {
781
782        return columnListInTempTable;
783    }
784
785    public void setPxGranule(TPxGranule pxGranule) {
786        this.pxGranule = pxGranule;
787    }
788
789    public TPxGranule getPxGranule() {
790
791        return pxGranule;
792    }
793
794    private TPxGranule pxGranule;
795    private TFlashback flashback;
796
797    public void setFlashback(TFlashback flashback) {
798        this.flashback = flashback;
799    }
800
801    public TFlashback getFlashback() {
802        return flashback;
803    }
804
805    private int parenthesisCount = 0;
806    private int parenthesisAfterAliasCount = 0;
807    private boolean tableKeyword = false;
808    private boolean onlyKeyword = false;
809    private boolean npathOnClauseTable = false;
810
811    /**
812     * Redshift array-unnesting positional index alias.
813     * <p>
814     * When a Redshift array column is unnested in the FROM clause with a
815     * positional index, e.g.
816     * <pre>FROM schema.tbl t, t.array_col AS element AT idx</pre>
817     * this table represents {@code t.array_col} with element alias
818     * {@code element} (the regular {@link #getAliasClause() aliasClause}) and
819     * {@code idx} captured here as the array index alias.
820     */
821    private TObjectName arrayIndexAlias;
822
823    public TObjectName getArrayIndexAlias() {
824        return arrayIndexAlias;
825    }
826
827    public void setArrayIndexAlias(TObjectName arrayIndexAlias) {
828        this.arrayIndexAlias = arrayIndexAlias;
829    }
830
831    /**
832     * Redshift SUPER object unpivoting source, e.g.
833     * <pre>FROM c.c_orders AS o, UNPIVOT o AS val AT attr</pre>
834     * When {@code true} this table represents the unpivoted SUPER expression:
835     * the regular alias is the value alias and {@link #getArrayIndexAlias()}
836     * (from {@code AT}) is the attribute-name alias.
837     */
838    private boolean superUnpivot = false;
839
840    public boolean isSuperUnpivot() {
841        return superUnpivot;
842    }
843
844    public void setSuperUnpivot(boolean superUnpivot) {
845        this.superUnpivot = superUnpivot;
846    }
847
848    /**
849     * Marks this table as coming from a Teradata NPath function's ON clause.
850     * This is used for data lineage to trace back to the source table inside NPath.
851     */
852    public void setNPathOnClauseTable(boolean npathOnClauseTable) {
853        this.npathOnClauseTable = npathOnClauseTable;
854    }
855
856    /**
857     * Returns true if this table comes from a Teradata NPath function's ON clause.
858     */
859    public boolean isNPathOnClauseTable() {
860        return npathOnClauseTable;
861    }
862
863    public void setTableKeyword(boolean tableKeyword) {
864        this.tableKeyword = tableKeyword;
865    }
866
867    public void setOnlyKeyword(boolean onlyKeyword) {
868        this.onlyKeyword = onlyKeyword;
869    }
870
871    public boolean isTableKeyword() {
872
873        return tableKeyword;
874    }
875
876    public boolean isOnlyKeyword() {
877        return onlyKeyword;
878    }
879
880    public void setParenthesisCount(int parenthesisCount) {
881        this.parenthesisCount = parenthesisCount;
882    }
883
884    public void setParenthesisAfterAliasCount(int parenthesisAfterAliasCount) {
885        this.parenthesisAfterAliasCount = parenthesisAfterAliasCount;
886    }
887
888    public int getParenthesisCount() {
889
890        return parenthesisCount;
891    }
892
893    public int getParenthesisAfterAliasCount() {
894        return parenthesisAfterAliasCount;
895    }
896
897    private TMergeSqlStatement outputMerge;
898
899    public void setOutputMerge(TMergeSqlStatement outputMerge) {
900        this.outputMerge = outputMerge;
901    }
902
903    public TMergeSqlStatement getOutputMerge() {
904
905        return outputMerge;
906    }
907
908    private TPivotedTable pivotedTable;
909
910    public void setPivotedTable(TPivotedTable pivotedTable) {
911        this.pivotedTable = pivotedTable;
912    }
913
914    public TPivotedTable getPivotedTable() {
915
916        return pivotedTable;
917    }
918
919    private ETableEffectType effectType;
920
921    public void setEffectType(ETableEffectType effectType) {
922        this.effectType = effectType;
923    }
924
925    public ETableEffectType getEffectType() {
926
927        return effectType;
928    }
929
930    private TTable linkTable;
931
932    public void setLinkTable(TTable linkTable) {
933        this.linkTable = linkTable;
934        isLinkTable = (this.linkTable != null);
935    }
936
937    public TTable getLinkTable() {
938
939        return linkTable;
940    }
941
942    public boolean isLinkTable() {
943        return isLinkTable;
944    }
945
946    /**
947     * @deprecated As of v1.8.4.6, set in {@link #setLinkTable}
948     */
949    public void setLinkTable(boolean isLinkTable) {
950
951        this.isLinkTable = isLinkTable;
952    }
953
954    private boolean isLinkTable;
955
956
957    public String getAliasName(){
958        if (getAliasClause() == null) return "";
959        TObjectName aliasName = getAliasClause().getAliasName();
960        return (aliasName == null) ? "" : aliasName.toString();
961    }
962
963    public boolean equalByName(String pTableName){
964        if (getAliasClause() != null){
965            return SQLUtil.sameName(this.dbvendor, ESQLDataObjectType.dotTable, getAliasClause().getAliasName().toString(), pTableName);
966        }else{
967            return SQLUtil.compareIdentifier(this.dbvendor, ESQLDataObjectType.dotTable, getName(), pTableName);
968        }
969    }
970
971    private TPTNodeList<THiveKeyValueProperty> tableProperties;
972
973    public void setTableProperties(TPTNodeList<THiveKeyValueProperty> tableProperties) {
974        this.tableProperties = tableProperties;
975    }
976
977    /**
978      *
979      * @return hive table property list
980      */
981
982    public TPTNodeList<THiveKeyValueProperty> getTableProperties() {
983        return tableProperties;
984    }
985
986    private ArrayList<TLateralView> lateralViewList = null;
987
988    public void setLateralViewList(ArrayList<TLateralView> lateralViewList) {
989        this.lateralViewList = lateralViewList;
990    }
991
992    public ArrayList<TLateralView> getLateralViewList() {
993        return lateralViewList;
994
995    }
996
997    private TTableSample tableSample;
998
999    public void setTableSample(TTableSample tableSample) {
1000        this.tableSample = tableSample;
1001    }
1002
1003    public TTableSample getTableSample() {
1004
1005        return tableSample;
1006    }
1007
1008    public void setPartitionExtensionClause(TPartitionExtensionClause partitionExtensionClause) {
1009        this.partitionExtensionClause = partitionExtensionClause;
1010    }
1011
1012    private TPartitionExtensionClause partitionExtensionClause;
1013
1014    public TPartitionExtensionClause getPartitionExtensionClause() {
1015        return partitionExtensionClause;
1016    }
1017
1018    public void setOuterClause(TInformixOuterClause outerClause) {
1019        this.outerClause = outerClause;
1020    }
1021
1022    public TInformixOuterClause getOuterClause() {
1023
1024        return outerClause;
1025    }
1026
1027    private TInformixOuterClause outerClause;
1028
1029    private TXmlTable xmlTable;
1030
1031    private TFromTableList fromTableList;
1032
1033    public void setFromTableList(TFromTableList fromTableList) {
1034        this.fromTableList = fromTableList;
1035    }
1036
1037    public TFromTableList getFromTableList() {
1038
1039        return fromTableList;
1040    }
1041
1042    public TXmlTable getXmlTable() {
1043        return xmlTable;
1044    }
1045
1046    public void setXmlTable(TXmlTable xmlTable) {
1047
1048        this.xmlTable = xmlTable;
1049    }
1050
1051    private TOpenQuery openquery = null;
1052
1053    public void setTableHintList(TPTNodeList<TTableHint> tableHintList) {
1054        this.tableHintList = tableHintList;
1055    }
1056
1057
1058    public TPTNodeList<TTableHint> getTableHintList() {
1059
1060        return tableHintList;
1061    }
1062
1063    private TPTNodeList<TTableHint> tableHintList;
1064
1065    public TOpenQuery getOpenquery() {
1066        return openquery;
1067    }
1068
1069    public TSelectSqlStatement getSubquery() {
1070        return subquery;
1071    }
1072
1073    public void setOpenquery(TOpenQuery openquery) {
1074
1075        this.openquery = openquery;
1076    }
1077
1078    public void setOpenDatasource(TOpenDatasource openDatasource) {
1079        this.openDatasource = openDatasource;
1080    }
1081
1082    /**
1083     * Valid when {@link #tableType} is ftt_opendatasource.
1084     * @return
1085     */
1086    public TOpenDatasource getOpenDatasource() {
1087
1088        return openDatasource;
1089    }
1090
1091    private TOpenDatasource openDatasource = null;
1092
1093    public void setOpenXML(TOpenXML openXML) {
1094        this.openXML = openXML;
1095    }
1096
1097    public TOpenXML getOpenXML() {
1098
1099        return openXML;
1100    }
1101
1102    private TOpenXML openXML = null;
1103
1104    public TOpenRowSet getOpenRowSet() {
1105        return openRowSet;
1106    }
1107
1108    public void setOpenRowSet(TOpenRowSet openRowSet) {
1109
1110        this.openRowSet = openRowSet;
1111    }
1112
1113    private TOpenRowSet openRowSet = null;
1114
1115    public TContainsTable getContainsTable() {
1116        return containsTable;
1117    }
1118
1119    public void setContainsTable(TContainsTable containsTable) {
1120        this.containsTable = containsTable;
1121    }
1122
1123    private TContainsTable containsTable = null;
1124
1125    public TFunctionCall getFuncCall() {
1126        return funcCall;
1127    }
1128
1129    public void setFuncCall(TFunctionCall funcCall) {
1130        this.funcCall = funcCall;
1131    }
1132
1133
1134    private TFunctionCall funcCall = null;
1135
1136    private TMultiTargetList rowList;
1137
1138    /**
1139     * @deprecated As of v2.3.6.9, please use {@link #getValueClause()} instead
1140     *
1141     * row constructor like this: '(' RW_VALUES MultiTargets ')'
1142     * @return     TMultiTargetList
1143     */
1144    public TMultiTargetList getRowList() {
1145        return rowList;
1146    }
1147
1148    public boolean isBaseTable(){
1149       boolean retval = (tableType == ETableSource.objectname);
1150       if (retval){
1151          if (isCTEName()){
1152              retval = false;
1153          }
1154       }
1155
1156       if (retval){
1157           if (getFullName().startsWith("@")) {
1158               retval = false;
1159           }
1160       }
1161        return retval;
1162    }
1163    
1164    public void setCteColomnReferences(TObjectNameList cteColomnReferences) {
1165        this.cteColomnReferences = cteColomnReferences;
1166    }
1167
1168    private TObjectNameList cteColomnReferences = null;
1169
1170    public TObjectNameList getCteColomnReferences() {
1171        return cteColomnReferences;
1172    }
1173
1174    public void setObjectNameReferences(TObjectNameList objectNameReferences) {
1175
1176        this.objectNameReferences = objectNameReferences;
1177    }
1178
1179   private TCTE CTE;
1180
1181    public boolean setCTE(TCTE pCTE) {
1182        if (pCTE == null){
1183            this.CTE = null;
1184            return true;
1185        }
1186
1187        if ((!pCTE.isRecursive()) && (pCTE.getSubquery() != null) && (TParseTreeNode.subNodeInNode(this,pCTE.getSubquery()))){
1188            // 如果这个table是属于一个CTE的子查询,那么不再设置CTE,因为该table不可能是该CTE的引用, 但前提条件是
1189            // 1. 该 subquery 非 combined query
1190            // 2. 如果该 subquery 是 combined query , 该 table 属于第一个subquery 中的 table
1191
1192            // 如果不是以上两种情况,那么该table就是该CTE的引用,需要返回 true
1193            // refer to: public void testSearchTable1()
1194
1195            if (!pCTE.getSubquery().isCombinedQuery()) return false;
1196
1197            if (TParseTreeNode.subNodeInNode(this,pCTE.getSubquery().getLeftStmt())){
1198                return false;
1199            }
1200
1201        }
1202
1203        this.CTE = pCTE;
1204        return true;
1205    }
1206
1207    public TCTE getCTE() {
1208
1209        return CTE;
1210    }
1211
1212    public boolean isCTEName() {
1213
1214        return isCTEName;
1215    }
1216
1217    public void setCTEName(boolean CTEName) {
1218        isCTEName = CTEName;
1219    }
1220
1221    private boolean isCTEName = false;
1222
1223    public TSelectSqlStatement subquery = null;
1224    private THiveFromQuery hiveFromQuery;
1225
1226    public void setHiveFromQuery(THiveFromQuery hiveFromQuery) {
1227        this.hiveFromQuery = hiveFromQuery;
1228    }
1229
1230    /**
1231     * @deprecated As of v2.1.0.0, please use {@link #getSubquery()}
1232     * @return
1233     */
1234    public THiveFromQuery getHiveFromQuery() {
1235
1236        return hiveFromQuery;
1237    }
1238
1239    public TExpression getTableExpr() {
1240        return tableExpr;
1241    }
1242
1243    public void setTableExpr(TExpression tableExpr) {
1244        this.tableExpr = tableExpr;
1245    }
1246
1247    private TExpression tableExpr;
1248
1249    public void setTableType(ETableSource tableType) {
1250        this.tableType = tableType;
1251    }
1252
1253    /**
1254     *
1255     * @return what's kind of type this table is.
1256     *<ul>
1257     * <li>{@link ETableSource#objectname}, in from clause, a simple table/view name, reference: {@link TTable#tableName}<li>
1258     * <li>{@link ETableSource#subquery}, is a subquery that retrieves rows from the database, also known as derived table. reference: {@link TTable#subquery}</li>
1259     * <li>{@link ETableSource#tableExpr},it's usually a table-valued expression., reference: {@link TTable#tableExpr}</li>
1260     * <li>{@link ETableSource#function}, it's usually a table-valued function., reference: {@link TTable#funcCall}</li>
1261     * <li>{@link ETableSource#rowList}, it's constructed rows, reference: {@link TTable#rowList}</li>
1262     * <li>{@link ETableSource#containsTable}, CONTAINSTABLE clause of sql server. reference: {@link TTable#containsTable}, type of {@link TContainsTable}</li>
1263     * <li>{@link ETableSource#freetextTable}, FREETEXTTABLE  clause of sql server. reference: {@link TTable#containsTable}, type of {@link TContainsTable}</li>
1264     * <li>{@link ETableSource#openrowset}, OPENROWSET clause of sql server. reference: {@link TTable#openRowSet}, type of {@link TOpenRowSet}</li>
1265     * <li>{@link ETableSource#openxml}, OPENXML clause of sql server. reference: {@link TTable#openXML}, type of {@link TOpenXML }</li>
1266     * <li>{@link ETableSource#opendatasource}, OPENDATASOURCE clause of sql server. reference: {@link TTable#openDatasource}, type of {@link TOpenDatasource}</li>
1267     * <li>{@link ETableSource#openquery}, OPENQUERY clause of sql server. reference: {@link TTable#openquery}, type of (@link TOpenQuery)</li>
1268     * </ul>
1269     */
1270    public ETableSource getTableType() {
1271
1272        return tableType;
1273    }
1274
1275    private ETableSource tableType;
1276    
1277    public void setTableName(TObjectName tableName) {
1278        this.tableName = tableName;
1279        tableType = ETableSource.objectname;
1280        this.tableName.splitNameInQuotedIdentifier();
1281        if (this.getStartToken() == null){
1282            this.setStartToken(tableName.getStartToken());
1283        }
1284
1285        if (this.getEndToken() == null){
1286            this.setEndToken(tableName.getEndToken());
1287        }
1288    }
1289
1290    public TObjectName getTableName() {
1291        TObjectName ret = tableName;
1292
1293        if (tableType == null) return ret;
1294
1295        switch (tableType){
1296            case tableExpr:
1297                if (tableExpr.getExpressionType() == EExpressionType.function_t){
1298                    ret = tableExpr.getFunctionCall().getFunctionName();
1299                }
1300                break;
1301            case function:
1302                ret = getFuncCall().getFunctionName();
1303                break;
1304            case openrowset:
1305                ret = TObjectName.createObjectName (this.dbvendor, EDbObjectType.table,new TSourceToken("openrowset"));
1306                break;
1307            case rowList:
1308                ret = TObjectName.createObjectName (this.dbvendor, EDbObjectType.table,new TSourceToken("(values_table)"));
1309                break;
1310            case subquery:
1311                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("subquery"));
1312                break;
1313            case td_unpivot:
1314                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("td_unpivot"));
1315                break;
1316            case pivoted_table:
1317                // Check if this is an UNPIVOT to use the correct suffix
1318                String pivotSuffix = "(piviot_table)";
1319                if (getPivotedTable() != null && getPivotedTable().getPivotClause() != null
1320                    && getPivotedTable().getPivotClause().getType() == TPivotClause.unpivot) {
1321                    pivotSuffix = "(unpivot_table)";
1322                }
1323                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken(tableName+pivotSuffix));
1324                break;
1325            case xmltable:
1326                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("xmltable"));
1327                break;
1328            case jsonTable:
1329                ret = getJsonTable().getFunctionName();// TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("jsontable"));//
1330                break;
1331            case containsTable:
1332                if (containsTable.getType() == TContainsTable.containstable){
1333                    ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("containsTable"));
1334                }else {
1335                    ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("freetexttable"));
1336                }
1337                break;
1338            case opendatasource:
1339                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("opendatasource"));
1340                break;
1341            case unnest:
1342                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken(getAliasName()+"(unnest table)"));
1343                break;
1344            case openxml:
1345                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("openxml"));
1346                break;
1347            case openquery:
1348                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("openquery"));
1349                break;
1350            case output_merge:
1351                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("merge"));
1352                break;
1353            case externalTable:
1354                ret = this.tableName;
1355                break;
1356            case join:
1357                ret = TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("join_expr"));
1358                break;
1359        }
1360        if (ret == null) {
1361            return TObjectName.createObjectName (this.dbvendor,EDbObjectType.table,new TSourceToken("unknown"));
1362        }
1363        else  return ret;
1364    }
1365
1366    private TObjectName tableName;
1367
1368    public TTable(TObjectName pobjectname){
1369           this.tableName = pobjectname;
1370           this.setStartToken(this.tableName.getStartToken());
1371           this.setEndToken(this.tableName.getEndToken());
1372    }
1373
1374
1375    public TTable(){
1376           this.tableName = null;
1377    }
1378
1379    public String getName() {
1380        if (tableName != null)
1381            return tableName.getObjectString();
1382        else
1383            return getTableName().toString();
1384    }
1385
1386
1387    public String getPrefixServer(){
1388       if (tableName != null) return tableName.getServerString();
1389       else return "";
1390    }
1391    public  String getPrefixDatabase(){
1392        if (tableName != null) return tableName.getDatabaseString();
1393        else return "";
1394    }
1395    public String getPrefixSchema(){
1396        if (tableName != null) return tableName.getSchemaString();
1397        else return "";
1398    }
1399
1400    public boolean isIncludeColumnAlias(){
1401       //  return (this.getAliasClause() != null);
1402        return false;
1403        // ToDo
1404    }
1405
1406
1407    public int searchColumnInAlias(TObjectName pColumn){
1408        if (getAliasClause() == null) return -1;
1409        return getAliasClause().searchColumn(pColumn);
1410    }
1411
1412    public boolean checkTableByName(String pTablename){
1413        boolean lcResult = false;
1414        String a,b,c;
1415        b = TBaseType.getTextWithoutQuoted(pTablename);
1416        if (this.getAliasClause() != null){
1417            a = TBaseType.getTextWithoutQuoted(this.getAliasName());
1418            lcResult = a.equalsIgnoreCase(b);
1419        }
1420        if (lcResult) return true;
1421        c = TBaseType.getTextWithoutQuoted(this.getTableName().toString());
1422        lcResult = c.equalsIgnoreCase(b);
1423        return lcResult;
1424    }
1425
1426    public boolean searchColumn(TSelectSqlStatement select, String tableName, TObjectName pColumn, boolean pMustIn){
1427        // pColumn maybe qualified, so check the table name at first
1428        boolean lcResult = false, isSameTable = false;
1429        if ( tableName.length() == 0){
1430            isSameTable = true;
1431        }else {
1432            isSameTable = checkTableByName(tableName);
1433        }
1434
1435        if (!isSameTable) return lcResult;
1436
1437        if (this.isBaseTable()){
1438            lcResult = select.fireOnMetaDatabaseTableColumn(this.getPrefixServer(),this.getPrefixDatabase(),this.getPrefixSchema(),this.getName(),pColumn.getColumnNameOnly());
1439        }else{
1440            if (this.getTableType() == ETableSource.subquery){
1441                if (this.isIncludeColumnAlias()){
1442                    lcResult = this.searchColumnInAlias(pColumn)>=0;
1443                }else{
1444                    lcResult = this.getSubquery().searchColumnInResultSet(pColumn,pMustIn);
1445                }
1446            }else if (this.isCTEName()){
1447                lcResult = this.getCTE().searchColumnInResultSet(select,this,pColumn,pMustIn);
1448            }
1449        }
1450
1451        if (lcResult){
1452            this.getLinkedColumns().addObjectName(pColumn);
1453            pColumn.setSourceTable(this);
1454        }else if (pMustIn){
1455            this.getLinkedColumns().addObjectName(pColumn);
1456            pColumn.setSourceTable(this);
1457            lcResult = true;
1458        }
1459
1460        if (!lcResult){
1461            if (this.getTableType() == ETableSource.pivoted_table){
1462                if (this.getLinkedColumns().size() > 0){
1463                    for(TObjectName c: this.getLinkedColumns()){
1464                        lcResult = c.toString().equalsIgnoreCase(pColumn.getColumnNameOnly());
1465                        if (lcResult) break;
1466                    }
1467                }
1468            }
1469        }
1470
1471        return lcResult;
1472    }
1473
1474    private TObjectNameList linkedColumns = null;
1475
1476    /**
1477     * @deprecated , this method is deprecated since version 3.3.1.0, don't use it in TSQLResolver2
1478     * @return
1479     */
1480    public TObjectNameList getLinkedColumns() {
1481        if (linkedColumns == null) {
1482            linkedColumns = new TObjectNameList();
1483            linkedColumns.setObjectType(TObjectName.ttobjColumn);
1484        }
1485        return linkedColumns;
1486    }
1487
1488
1489
1490    public String getFullNameWithAliasString() {
1491        if (getAliasClause() != null){
1492            return getFullName()+" "+getAliasClause().toString();
1493        }else{
1494            return getFullName();
1495        }
1496    }
1497
1498    public String getFullName() {
1499        if (tableName == null) return  null;
1500        return tableName.toString();
1501        /*
1502        if (tableName.getSchemaString() == null)
1503        {return this.getName();}
1504        else{
1505            return tableName.getSchemaString()+"."+this.getName();
1506        }
1507          */
1508
1509    }
1510
1511    /**
1512     *
1513     * @return column name related to this table.
1514     * @deprecated As of v1.6.0.1, use  {@link #getLinkedColumns()} instead
1515     */
1516    public TObjectNameList getObjectNameReferences() {
1517        if (objectNameReferences == null){
1518            objectNameReferences = new TObjectNameList();
1519            objectNameReferences.setObjectType(TObjectName.ttobjColumn);
1520        }
1521        return objectNameReferences;
1522    }
1523
1524    private TPivotClause pivotClause = null;
1525
1526    public void setPivotClause(TPivotClause pivotClause) {
1527        this.pivotClause = pivotClause;
1528    }
1529
1530    /**
1531     * @deprecated As of v1.6.2.4, replaced by {@link gudusoft.gsqlparser.nodes.TPivotedTable}
1532     * @return
1533     */
1534    public TPivotClause getPivotClause() {
1535
1536        return pivotClause;
1537    }
1538
1539    /**
1540     * Stored all column names that belong to this table.
1541     */
1542    private TObjectNameList objectNameReferences = null;
1543
1544    public TTableReferenceList tablerefs = new TTableReferenceList();
1545
1546    private TDataChangeTable datachangeTable = null;
1547
1548    public void setDatachangeTable(TDataChangeTable datachangeTable) {
1549        this.datachangeTable = datachangeTable;
1550    }
1551
1552    /**
1553     * DB2 data change
1554     * @return
1555     */
1556    public TDataChangeTable getDatachangeTable() {
1557        return datachangeTable;
1558    }
1559
1560
1561    public boolean isTableRefBelongToThisTable(TTableReference tableref){
1562
1563        boolean retval = (this.tableName == tableref.objectname);
1564        if (retval) {return retval;}
1565        if (SQLUtil.sameName(this.dbvendor, ESQLDataObjectType.dotTable, this.tableName.getObjectString(), tableref.objectname.getObjectString())){
1566            if ((this.tableName.getSchemaString() == null)
1567                ||(tableref.objectname.getSchemaString() == null)
1568                    ) {
1569                retval = true;
1570            }else{
1571                retval = SQLUtil.sameName(this.dbvendor, ESQLDataObjectType.dotSchema, this.tableName.getSchemaString(), tableref.objectname.getSchemaString());
1572            }
1573        }
1574        return retval;
1575    }
1576
1577    public void accept(TParseTreeVisitor v){
1578        v.preVisit(this);
1579
1580        v.postVisit(this);
1581    }
1582
1583    public void setColumnDefinitions(TColumnDefinitionList columnDefinitions) {
1584        this.columnDefinitions = columnDefinitions;
1585    }
1586
1587    public void acceptChildren(TParseTreeVisitor v){
1588        v.preVisit(this);
1589
1590        switch(getTableType()){
1591            case objectname:{
1592                getTableName().acceptChildren(v);
1593                if (getFlashback() != null){
1594                    getFlashback().acceptChildren(v);
1595                }
1596                break;
1597            }
1598            case tableExpr:{
1599                getTableExpr().acceptChildren(v);
1600                break;
1601            }
1602            case subquery:{
1603                getSubquery().acceptChildren(v);
1604                break;
1605            }
1606            case function:{
1607                getFuncCall().acceptChildren(v);
1608                break;
1609            }
1610            case pivoted_table:{
1611                if (this.getEffectType() == ETableEffectType.tetPivot) break;
1612                getPivotedTable().acceptChildren(v);
1613                break;
1614            }
1615            case output_merge:{
1616                if (getOutputMerge() != null) getOutputMerge().acceptChildren(v);
1617                //e_table_reference.setTextContent(node.getOutputMerge().toString());
1618                break;
1619            }
1620            case containsTable:{
1621                getContainsTable().acceptChildren(v);
1622                break;
1623            }
1624
1625            case openrowset:{
1626                getOpenRowSet().acceptChildren(v);
1627                break;
1628            }
1629
1630            case openxml:{
1631                getOpenXML().acceptChildren(v);
1632                break;
1633            }
1634
1635            case opendatasource:{
1636                getOpenDatasource().acceptChildren(v);
1637                break;
1638            }
1639
1640            case openquery:{
1641                getOpenquery().acceptChildren(v);
1642                break;
1643            }
1644
1645            case datachangeTable:{
1646                getDatachangeTable().acceptChildren(v);
1647                break;
1648            }
1649            case rowList:{
1650                getValueClause().acceptChildren(v);
1651                break;
1652            }
1653            case xmltable:{
1654                getXmlTable().acceptChildren(v);
1655                break;
1656            }
1657            case jsonTable:{
1658                getJsonTable().acceptChildren(v);
1659                break;
1660            }
1661            case informixOuter:{
1662                getOuterClause().acceptChildren(v);
1663                break;
1664            }
1665
1666            case table_ref_list:{
1667                getFromTableList().acceptChildren(v);
1668                break;
1669            }
1670            case hiveFromQuery:{
1671                getHiveFromQuery().acceptChildren(v);
1672                break;
1673            }
1674            case externalTable:
1675                this.columnDefinitions.acceptChildren(v);
1676                break;
1677            case join:
1678                this.joinExpr.acceptChildren(v);
1679                break;
1680            case unnest:
1681                this.getUnnestClause().acceptChildren(v);
1682                break;
1683            default:
1684                //sb.append(node.toString().replace(">","&#62;").replace("<","&#60;"));
1685                break;
1686
1687        }
1688
1689
1690        if (getPxGranule() != null){
1691            getPxGranule().acceptChildren(v);
1692        }
1693
1694        if (getTableSample() != null){
1695           getTableSample().acceptChildren(v);
1696        }
1697
1698        if (getAliasClause() != null){
1699            getAliasClause().acceptChildren(v);
1700        }
1701
1702
1703        if (getTableHintList() != null){
1704            for(int i=0;i<getTableHintList().size();i++){
1705                TTableHint tableHint = getTableHintList().getElement(i);
1706                tableHint.acceptChildren(v);
1707            }
1708        }
1709
1710        if (getLateralViewList() != null){
1711            for(TLateralView lateralView:getLateralViewList()){
1712                lateralView.acceptChildren(v);
1713            }
1714        }
1715
1716
1717        v.postVisit(this);
1718    }
1719
1720    public void setRowList(TMultiTargetList rowList) {
1721        this.rowList = rowList;
1722    }
1723
1724    public void setSubquery(TSelectSqlStatement subquery) {
1725        this.subquery = subquery;
1726    }
1727
1728    public void setLinkedColumns(TObjectNameList linkedColumns) {
1729        this.linkedColumns = linkedColumns;
1730    }
1731
1732    public void setTablerefs(TTableReferenceList tablerefs) {
1733        this.tablerefs = tablerefs;
1734    }
1735
1736    private boolean starColumnExpanded = false;
1737
1738    private ArrayList<String> expandedStarColumns = new ArrayList<String>();
1739
1740    private void getExpandStarColumnsFromSubquery(TSelectSqlStatement subquery, ArrayList<String> expandedStarColumns){
1741
1742        for(TResultColumn resultColumn:subquery.getResultColumnList()){
1743            if (resultColumn.toString().endsWith("*")){
1744                TTable srcTable  = resultColumn.getExpr().getObjectOperand().getSourceTable();
1745                if ( srcTable!= null){
1746                    ArrayList<String> list = srcTable.getExpandedStarColumns();
1747                    expandedStarColumns.addAll(list);
1748                }
1749            }else{
1750                expandedStarColumns.add(resultColumn.getDisplayName());
1751            }
1752        }
1753    }
1754
1755    /**
1756     * If a star column is linked to this table, use this method to returns all underlying columns that represented by
1757     * the star column.
1758     * <br>
1759     * <br> The returned column always prefixed with
1760     * <br> 1. the table alias.
1761     * <br> 2. the table name
1762     * <br> 3. the alias of query (if the table is a subquery)
1763     * <br> 4. empty if the no alias is specified for a subquery
1764     *
1765     * @return a list of columns
1766     */
1767    public ArrayList<String> getExpandedStarColumns(){
1768        if (starColumnExpanded) return expandedStarColumns;
1769
1770        switch (getTableType()){
1771            case objectname:
1772                if (this.isCTEName()){
1773                    if (this.getCteColomnReferences()!=null){
1774                        for(TObjectName n:this.getCteColomnReferences()){
1775                            expandedStarColumns.add(n.toString());
1776                        }
1777                    }else if (this.getCTE().getSubquery() != null){
1778                        this.getExpandStarColumnsFromSubquery(this.getCTE().getSubquery(),this.expandedStarColumns);
1779                    }
1780                }else{
1781                    if (this.getSqlEnv() != null){
1782                        ArrayList<String> columns = this.getSqlEnv().getColumnsInTable(this.getPrefixDatabase() +"."+this.getPrefixSchema()+"."+this.getName(),false);
1783                        if (columns != null) expandedStarColumns = columns;
1784                        if (this.getAliasClause() != null){
1785                            //replace table name with alias
1786                        }
1787                    }
1788                    if ((expandedStarColumns.size() == 0)&&(getLinkedColumns().size()>0)){
1789                        for(TObjectName linkColumn:getLinkedColumns()){
1790                            if (linkColumn.toString().endsWith("*")) continue;
1791                            String s = linkColumn.getColumnNameOnly();
1792                            if (this.getAliasClause() != null){
1793                                s = this.getAliasName()+"."+s;
1794                            }else{
1795                                s = this.getName()+"."+s;
1796                            }
1797                            if (expandedStarColumns.indexOf(s) == -1) expandedStarColumns.add(s);
1798                        }
1799                    }
1800                }
1801
1802                break;
1803            case subquery:
1804                this.getExpandStarColumnsFromSubquery(this.getSubquery(),this.expandedStarColumns);
1805                break;
1806            default:
1807                break;
1808        }
1809
1810        starColumnExpanded = true;
1811        return expandedStarColumns;
1812    }
1813
1814//    @Override
1815//    public String toString(){
1816//        if (getAliasClause() != null) return getAliasClause().toString();
1817//
1818//        switch (getTableType()){
1819//            case objectname:
1820//                return getName().toString();
1821//                break;
1822//            default:
1823//
1824//                break;
1825//        }
1826//    }
1827
1828    @Override
1829    public String toString(){
1830        String ret = super.toString();
1831        if (ret != null) return  ret;
1832        if (tableName != null) return tableName.getObjectString();
1833        return null;
1834    }
1835
1836}