001package gudusoft.gsqlparser.nodes;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.sqlenv.TSQLTable;
005import gudusoft.gsqlparser.visitors.TColumnNameVisitor;
006
007import java.util.ArrayList;
008
009/**
010*  use the PIVOT and UNPIVOT relational operators to change a table-valued expression into another table. 
011*/
012
013public class TPivotClause extends TNodeWithAliasClause implements IRelation {
014
015
016    ArrayList<TAttributeNode> relationAttributes = new ArrayList<>();
017    @Override
018    public ArrayList<TAttributeNode> getAttributes(){
019        return relationAttributes;
020    }
021
022    @Override
023    public int size(){
024        return relationAttributes.size();
025    }
026
027    @Override
028    public String getRelationName(){
029        return displayName;
030    };
031
032    private String displayName;
033    public String getDisplayName(){
034        return displayName;
035    }
036    public void initAttributes(){
037        displayName = "";
038        ArrayList<String> columns = new ArrayList<>();
039
040        switch (getType()) {
041            case pivot:
042                displayName = TTable.PIVOT_CLAUSE_ALIAS;
043                if (pivotInClause.getItems() != null){
044                    for(TResultColumn resultColumn: pivotInClause.getItems()){
045                        columns.add(resultColumn.getDisplayName());
046                    }
047                }
048                break;
049            case unpivot:
050                displayName = TTable.UNPIVOT_CLAUSE_ALIAS;
051                break;
052        }
053
054
055        if (getAliasClause() != null){
056            displayName = getAliasClause().getAliasName().toString();
057            if (getAliasClause().getColumns() != null){
058                columns.clear();
059                for(TObjectName column:getAliasClause().getColumns()){
060
061                    columns.add(column.toString());
062                }
063            }
064        }
065
066        for(String c:columns){
067            TAttributeNode node = new TAttributeNode(displayName+"."+c,pivotTable);
068            //relationAttributes.add(node);
069            TAttributeNode.addNodeToList(node,relationAttributes);
070        }
071
072    }
073
074
075    public final static int pivot = 1;
076    public final static int unpivot = 2;
077
078    private int type = pivot;
079
080    public TTable getPivotTable() {
081        return pivotTable;
082    }
083
084    private TTable pivotTable = null;
085
086
087//    private TAliasClause aliasClause = null;
088//
089//    @Override
090//    public TAliasClause getAliasClause() {
091//        return aliasClause;
092//    }
093//
094//    @Override
095//    public void setAliasClause(TAliasClause aliasClause) {
096//
097//        this.aliasClause = aliasClause;
098//    }
099
100    private TPivotInClause pivotInClause;
101
102    /**
103     * The names of the columns this operator generates, in text order, duplicates included: for UNPIVOT its value
104     * and FOR columns, for PIVOT the names of its alias column list or one per IN item. The rule is resolver2's
105     * ({@code PivotNamespace.generatedColumnNames}), so a consumer that publishes a pivot's columns names them as
106     * a reference to them is resolved (plan 09 slice 10).
107     */
108    public java.util.List<String> getGeneratedColumnNames() {
109        return gudusoft.gsqlparser.resolver2.namespace.PivotNamespace.generatedColumnNames(this);
110    }
111
112    /**
113     * For each name of {@link #getGeneratedColumnNames()}, whether it is the column's stored name as written: the
114     * literal of an unaliased IN value in a dialect that names the column after it ({@code IN ('direct')} in Oracle
115     * names the column {@code 'direct'}, referenced as {@code "'direct'"}), never an identifier spelling to fold.
116     */
117    public java.util.List<Boolean> getGeneratedColumnStored() {
118        return gudusoft.gsqlparser.resolver2.namespace.PivotNamespace.generatedColumnsStored(this);
119    }
120
121    public TPivotInClause getPivotInClause() {
122        return pivotInClause;
123    }
124
125    private TUnpivotInClause unpivotInClause;
126
127    public TUnpivotInClause getUnpivotInClause() {
128        return unpivotInClause;
129    }
130
131    private TResultColumnList aggregation_function_list;
132    /**
133     * @deprecated since 1.7.1.1
134     */
135    private TResultColumnList in_result_list;
136
137    private TObjectNameList pivotColumnList;
138
139    public TObjectNameList getPivotColumnList() {
140        return pivotColumnList;
141    }
142
143    /**
144     * @deprecated since 1.7.1.1, use {@link #getPivotInClause} instead
145     * @return result column list
146     */
147    public TResultColumnList getIn_result_list() {
148        return in_result_list;
149    }
150
151    public TResultColumnList getAggregation_function_list() {
152
153        return aggregation_function_list;
154    }
155
156    public void setType(int type) {
157        this.type = type;
158    }
159
160    public int getType() {
161
162        return type;
163    }
164
165    private TFunctionCall aggregation_function = null;
166    /**
167     * @deprecated since 1.7.1.1, use  {@link #valueColumnList} instead
168     */
169    private TObjectName valueColumn = null;
170    private TObjectNameList valueColumnList = null;
171
172    public TObjectNameList getValueColumnList() {
173        return valueColumnList;
174    }
175
176    /**
177     * @deprecated since 1.7.1.1, use {@link #getPivotColumnList} instead.
178     */
179    private TObjectName pivotColumn = null;
180    private TObjectNameList columnList = null;
181
182    /**
183     *
184     * @return Is a system or user-defined aggregate function that accepts one or more inputs. 
185     */
186    public TFunctionCall getAggregation_function() {
187        return aggregation_function;
188    }
189
190    /**
191     *
192     * @return     In the PIVOT clause, lists the values in the pivot_column that will become the column names of the output table. The list cannot specify any column names that already exist in the input table_source that is being pivoted.
193     *  In the UNPIVOT clause, lists the columns in table_source that will be narrowed into a single pivot_column.
194     */
195    public TObjectNameList getColumnList() {
196        return columnList;
197    }
198
199    /**
200     * @deprecated since 1.7.1.1 , use {@link #getPivotColumnList} instead.
201     * @return Is the pivot column of the PIVOT operator. 
202     */
203    public TObjectName getPivotColumn() {
204        return pivotColumn;
205    }
206
207    /**
208     * @deprecated  since 1.7.1.1, use {@link #getValueColumnList} instead.
209     * @return  Is the value column of the PIVOT operator.
210     * When used with UNPIVOT, value_column cannot be the name of an existing column in the input table_source.
211     */
212    public TObjectName getValueColumn() {
213        return valueColumn;
214    }
215
216    public void init(Object arg1,Object arg2){
217        if (arg1 instanceof TFunctionCall){
218            aggregation_function = (TFunctionCall)arg1; // pivot clause, sql server
219        }else if (arg1 instanceof TResultColumnList){
220            aggregation_function_list = (TResultColumnList)arg1; // pivot clause, oracle
221        }else if (arg1 instanceof TObjectNameList){
222           valueColumnList = (TObjectNameList)arg1; // unpivot clause
223        }else if (arg1 instanceof TObjectName){
224            valueColumn = (TObjectName)arg1;
225        }
226
227        if (arg2 instanceof TObjectName){
228            pivotColumn = (TObjectName)arg2;
229        }else if (arg2 instanceof TObjectNameList){
230            pivotColumnList = (TObjectNameList)arg2;
231        }
232    }
233
234    public void init(Object arg1,Object arg2,Object arg3){
235        init(arg1,arg2);
236        if (arg3 instanceof TUnpivotInClause){
237            unpivotInClause = (TUnpivotInClause)arg3;
238        } else if (arg3 instanceof TPivotInClause){
239            pivotInClause = (TPivotInClause)arg3;
240        }
241//        else if (arg3 instanceof TResultColumnList){
242//            in_result_list = (TResultColumnList)arg3;
243//        } else if (arg3 instanceof TObjectNameList){
244//            pivotColumnList = (TObjectNameList)arg3;
245//        }
246    }
247
248    public void doParse(TCustomSqlStatement psql, ESqlClause plocation){
249        TSQLTable sqlTable = null;
250        boolean addColumnFromAlias = false;
251
252        if (getAliasClause() != null){
253            getAliasClause().doParse(psql,plocation);
254
255            pivotTable = new TTable();
256
257            pivotTable.setTableName(getAliasClause().getAliasName());
258            pivotTable.setTableType(ETableSource.pivoted_table);
259            pivotTable.setEffectType(ETableEffectType.tetPivot);
260            psql.getTables().addTable(pivotTable);
261
262            pivotTable.setSourceTableOfPivot(psql.getTables().getTable(0));
263
264            if (psql.getSqlEnv() != null) {
265                sqlTable = psql.getSqlEnv().addTable(pivotTable.getFullName(), true);
266            }
267            if (getAliasClause().getColumns()!=null){
268                addColumnFromAlias = true;
269                for(TObjectName column:getAliasClause().getColumns()){
270                    pivotTable.getLinkedColumns().addObjectName(column);
271                    column.setSourceTable(pivotTable);
272                }
273
274                if (sqlTable != null){
275                    for(TObjectName column:getAliasClause().getColumns()){
276                        sqlTable.addColumn(column.toString());
277                    }
278                }
279            }
280        }else { // alias is not specified
281
282            pivotTable = new TTable();
283            if (getType() == pivot){
284                pivotTable.setTableName(TObjectName.createObjectName (psql.dbvendor, EDbObjectType.column_alias,new TSourceToken("pivot_alias")));
285            }else{
286                pivotTable.setTableName(TObjectName.createObjectName (psql.dbvendor,EDbObjectType.column_alias,new TSourceToken("unpivot_alias")));
287            }
288
289
290            pivotTable.setTableType(ETableSource.pivoted_table);
291            pivotTable.setEffectType(ETableEffectType.tetPivot);
292            psql.getTables().addTable(pivotTable);
293
294            pivotTable.setSourceTableOfPivot(psql.getTables().getTable(0));
295
296            if (psql.getSqlEnv() != null) {
297                sqlTable = psql.getSqlEnv().addTable(pivotTable.getFullName(), true);
298            }
299        }
300
301        switch (getType()){
302            case pivot:
303                if (aggregation_function_list != null){
304                    TColumnNameVisitor objectNameVisitor = new TColumnNameVisitor();
305                    aggregation_function_list.acceptChildren(objectNameVisitor);
306                    for(TObjectName objectName:objectNameVisitor.getObjectNames()){
307                        pivotTable.getSourceTableOfPivot().getLinkedColumns().addObjectName(objectName);
308                        objectName.setSourceTable(pivotTable.getSourceTableOfPivot());
309                    }
310                    aggregation_function_list.doParse(psql,plocation);
311                }else if (aggregation_function != null){
312                    TColumnNameVisitor objectNameVisitor = new TColumnNameVisitor();
313                    aggregation_function.getArgs().acceptChildren(objectNameVisitor);
314                    for(TObjectName objectName:objectNameVisitor.getObjectNames()){
315                        pivotTable.getSourceTableOfPivot().getLinkedColumns().addObjectName(objectName);
316                        objectName.setSourceTable(pivotTable.getSourceTableOfPivot());
317                    }
318
319                    aggregation_function.doParse(psql,plocation);
320                };
321
322                if (pivotColumnList != null){
323                    for(TObjectName objectName:pivotColumnList){
324                        pivotTable.getSourceTableOfPivot().getLinkedColumns().addObjectName(objectName);
325                        objectName.setSourceTable(pivotTable.getSourceTableOfPivot());
326                    }
327                }
328                pivotInClause.doParse(psql,plocation);
329                if (!addColumnFromAlias){
330                    pivotInClause.linkColumnToTable(pivotTable, sqlTable);
331                }
332
333                break;
334            case unpivot:
335                //valueColumnList.
336                if (pivotTable!=null){
337                    if (valueColumnList != null){
338                        for(TObjectName objectName: valueColumnList){
339                            pivotTable.getLinkedColumns().addObjectName(objectName);
340                            objectName.setSourceTable(pivotTable);
341                            if (sqlTable != null){
342                                sqlTable.addColumn(objectName.toString());
343                            }
344                        }
345                    }
346
347                    if (pivotColumnList!=null){
348                        for(TObjectName objectName: pivotColumnList){
349                            pivotTable.getLinkedColumns().addObjectName(objectName);
350                            objectName.setSourceTable(pivotTable);
351                            if (sqlTable != null){
352                                sqlTable.addColumn(objectName.toString());
353                            }
354                        }
355                    }
356                }
357                unpivotInClause.doParse(psql,plocation);
358                unpivotInClause.linkColumnToPivotSourceTable(pivotTable.getSourceTableOfPivot());
359                break;
360        }
361    }
362
363    public void accept(TParseTreeVisitor v){
364        v.preVisit(this);
365        v.postVisit(this);
366    }
367
368    public void acceptChildren(TParseTreeVisitor v){
369        v.preVisit(this);
370      //  pivotTable.acceptChildren(v);
371        switch (getType()){
372            case pivot:
373                if (aggregation_function_list != null){
374                    aggregation_function_list.acceptChildren(v);
375                }else if (aggregation_function != null){
376                    aggregation_function.acceptChildren(v);
377                }
378                pivotColumnList.acceptChildren(v);
379                if (pivotInClause != null){
380                    pivotInClause.acceptChildren(v);
381                }
382                break;
383            case unpivot:
384                valueColumnList.acceptChildren(v);
385                pivotColumnList.acceptChildren(v);
386                unpivotInClause.acceptChildren(v);
387                break;
388        }
389
390
391       if (getAliasClause() != null){
392            getAliasClause().acceptChildren(v);
393        }
394        v.postVisit(this);
395    }
396
397    public void setPivotInClause(TPivotInClause pivotInClause) {
398        this.pivotInClause = pivotInClause;
399    }
400
401    public void setUnpivotInClause(TUnpivotInClause unpivotInClause) {
402        this.unpivotInClause = unpivotInClause;
403    }
404
405    public void setAggregation_function_list(TResultColumnList aggregation_function_list) {
406        this.aggregation_function_list = aggregation_function_list;
407    }
408
409    public void setPivotColumnList(TObjectNameList pivotColumnList) {
410        this.pivotColumnList = pivotColumnList;
411    }
412
413    public void setAggregation_function(TFunctionCall aggregation_function) {
414        this.aggregation_function = aggregation_function;
415    }
416
417    public void setValueColumnList(TObjectNameList valueColumnList) {
418        this.valueColumnList = valueColumnList;
419    }
420
421    public void setColumnList(TObjectNameList columnList) {
422        this.columnList = columnList;
423    }
424}