001package gudusoft.gsqlparser.nodes;
002
003
004import gudusoft.gsqlparser.*;
005import gudusoft.gsqlparser.sqlenv.TSQLTable;
006import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
007
008import java.util.ArrayList;
009
010public class TPivotInClause extends TParseTreeNode {
011    private TResultColumnList items;
012    private TSelectSqlNode selectSqlNode;
013    private ArrayList<TExpressionList> valueList;
014
015    public ArrayList<TExpressionList> getValueList() {
016        return valueList;
017    }
018
019    public TSelectSqlStatement getSubQuery() {
020        return subQuery;
021    }
022
023    private TSelectSqlStatement subQuery;
024
025    public void linkColumnToTable(TTable table, TSQLTable sqlTable){
026
027        if (items != null){
028            for(TResultColumn resultColumn:items){
029                // An explicit alias names the generated column outright:
030                // IN ('direct' AS Store) produces a column called Store, not 'direct'.
031                // Oracle, Snowflake, BigQuery and Teradata all behave this way.
032                // Kept verbatim, quote state included, to match
033                // PivotNamespace.inListItemAlias - the name published here and the
034                // name resolver2 lets the column be resolved by must agree.
035                TObjectName itemAlias = (resultColumn.getAliasClause() == null)
036                        ? null : resultColumn.getAliasClause().getAliasName();
037                if (itemAlias != null && itemAlias.toString().length() > 0){
038                    TObjectName newObject = TObjectName.createObjectName (this.dbvendor, EDbObjectType.column, new TSourceToken(itemAlias.toString()));
039                    table.getLinkedColumns().addObjectName(newObject);
040                    newObject.setSourceTable(table);
041                }else if (resultColumn.getExpr().getExpressionType() == EExpressionType.simple_object_name_t){
042                    // the name follows PivotNamespace's rule (BigQuery "HOUSTON" is a string naming HOUSTON);
043                    // the operand keeps its own link to the pivot either way
044                    TObjectName operand = resultColumn.getExpr().getObjectOperand();
045                    String name = gudusoft.gsqlparser.resolver2.namespace.PivotNamespace.inListItemColumnName(resultColumn);
046                    if (name == null || name.equals(operand.toString())) {
047                        table.getLinkedColumns().addObjectName(operand);
048                    } else {
049                        TObjectName newObject = TObjectName.createObjectName (this.dbvendor, EDbObjectType.column, new TSourceToken(name));
050                        table.getLinkedColumns().addObjectName(newObject);
051                        newObject.setSourceTable(table);
052                    }
053                    operand.setSourceTable(table);
054                }else if (resultColumn.getExpr().getExpressionType() == EExpressionType.simple_constant_t){
055                    // the name follows PivotNamespace's rule: the literal as written (Oracle, Snowflake, Teradata),
056                    // else its value (BigQuery IN ('AA') names AA)
057                    TSourceToken value = resultColumn.getExpr().getConstantOperand().getValueToken();
058                    String name = gudusoft.gsqlparser.resolver2.namespace.PivotNamespace.inListItemColumnName(resultColumn);
059                    // IN (NULL) has no value token: the column is still named by the rule (Oracle names it NULL)
060                    TObjectName newObject= TObjectName.createObjectName (this.dbvendor, EDbObjectType.column,
061                            name == null || (value != null && name.equals(value.toString())) ? value
062                                    : new TSourceToken(name));
063                    table.getLinkedColumns().addObjectName(newObject);
064                    newObject.setSourceTable(table);
065                }
066            }
067
068            if (sqlTable != null){
069                for(TResultColumn resultColumn:items){
070                    sqlTable.addColumn(resultColumn.getDisplayName());
071                }
072            }
073        }else if (subQuery != null){
074            for(TResultColumn resultColumn:subQuery.getResultColumnList()){
075                TObjectName pivotColumn = TObjectName.createObjectName (this.dbvendor, EDbObjectType.column,new TSourceToken(resultColumn.getDisplayName()));
076                table.getLinkedColumns().addObjectName(pivotColumn);
077                pivotColumn.setSourceTable(table);
078                pivotColumn.setSourceColumn(resultColumn);
079                if (sqlTable != null){
080                    sqlTable.addColumn(pivotColumn.toString());
081                }
082            }
083        }
084    }
085
086    public TResultColumnList getItems() {
087        return items;
088    }
089
090    public void init(Object arg1){
091        if (arg1 instanceof TResultColumnList){
092            items = (TResultColumnList)arg1;
093        }else if (arg1 instanceof TSelectSqlNode){
094            selectSqlNode = (TSelectSqlNode)arg1;
095        }else{
096            valueList = (ArrayList<TExpressionList>)arg1;
097        }
098
099    }
100
101    public void doParse(TCustomSqlStatement psql, ESqlClause plocation){
102        if (selectSqlNode != null){
103            subQuery = new TSelectSqlStatement(psql.dbvendor);
104            subQuery.rootNode = selectSqlNode;
105            subQuery.setLocation(ESqlClause.pivot_in);
106            subQuery.doParseStatement(psql);
107        }
108    }
109
110    public void accept(TParseTreeVisitor v){
111        v.preVisit(this);
112        v.postVisit(this);
113    }
114
115    public void acceptChildren(TParseTreeVisitor v) {
116        v.preVisit(this);
117        if (items != null) items.accept(v);
118        if (subQuery != null) subQuery.accept(v);
119        v.postVisit(this);
120    }
121
122    public void setItems(TResultColumnList items) {
123        this.items = items;
124    }
125
126    public void setSubQuery(TSelectSqlStatement subQuery) {
127        this.subQuery = subQuery;
128    }
129}