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