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