001package gudusoft.gsqlparser.nodes;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.stmt.TDeleteSqlStatement;
005import gudusoft.gsqlparser.stmt.TInsertSqlStatement;
006import gudusoft.gsqlparser.stmt.TSelectSqlStatement;
007import gudusoft.gsqlparser.stmt.TUpdateSqlStatement;
008
009import java.util.ArrayList;
010
011/**
012 * A common table expression permits defining a result table with a table-name that can be specified as a table name in any FROM clause of the fullselect that follows.
013 *<p> Multiple common table expressions can be specified following the single WITH keyword.
014 *<p> Each common table expression specified can also be referenced by name in the FROM clause of subsequent common table expressions.
015 *<p> Syntax:
016 * <blockquote><pre>
017 * table-name [column-name [,...n]] AS (fullselect)</pre>
018 * </blockquote>
019*/
020public class TCTE extends TTable{
021
022    private boolean recursive = false;
023
024    public void setRecursive(boolean recursive) {
025        this.recursive = recursive;
026    }
027
028    public boolean isRecursive() {
029        return recursive;
030    }
031
032    public void initAttributesFromColumnList(){
033        if (this.getColumnList() != null){
034            int i = 0;
035            if ((this.getSubquery() != null)&&(this.getSubquery().getResultColumnList() != null)){
036                if (this.getSubquery().getResultColumnList().size() != this.getColumnList().size()){
037                    if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
038                        TBaseType.log(String.format("CTE: <%s> columns list size is not the same as select list in subQuery ", this.getTableName().toString())
039                                ,TLog.ERROR,this.getTableName());
040                    }
041                }
042            }
043            for(TObjectName column: this.getColumnList()){
044                if ((this.getSubquery() != null)&&(this.getSubquery().getResultColumnList() != null)){
045                    //  关联 subQuery 中 select list
046                       // relationAttributes.add(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this,this.getSubquery().getResultColumnList().getResultColumn(i) ));
047                    TAttributeNode.addNodeToList(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this,this.getSubquery().getResultColumnList().getResultColumn(i) ),relationAttributes);
048
049                }else{
050                        //relationAttributes.add(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this));
051                    TAttributeNode.addNodeToList(new TAttributeNode( this.getTableName().toString()+"." + column.toString() ,this),relationAttributes);
052                }
053                i++;
054            }
055            //
056            if ((this.getSubquery() != null)&&(this.getSubquery().isCombinedQuery())&&(this.getSubquery().getLeftStmt().getResultColumnList() != null)){
057                TSelectSqlStatement left = subquery.getLeftStmt();
058
059                String prefix = this.getTableName().toString()+".";
060                addNewAttributeFromSubQuery(left.getResultColumnList(),relationAttributes,prefix,this.getColumnList());
061                while (left.isCombinedQuery()){
062                    left = left.getLeftStmt();
063                    addNewAttributeFromSubQuery(left.getResultColumnList(),relationAttributes,prefix,this.getColumnList());
064                }
065            }
066        }
067
068        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
069            TBaseType.log(String.format("Prepare attributes for CTE: <%s> via column list",this.getTableName().toString()),TLog.DEBUG,this.getTableName());
070            for(TAttributeNode node:getAttributes()){
071                TBaseType.log(String.format("\tAttribute: <%s>, Select list column: <%s>",node.getName(),node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG);
072            }
073        }
074
075    }
076    public void initAttributesFromSubQuery(){
077        if (this.getSubquery() == null) return;
078        super.initAttributesFromSubquery(this.getSubquery(),this.getTableName().toString()+".");
079
080        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
081            TBaseType.log(String.format("Prepare attributes (num = %d) for CTE: <%s> via subQuery",getAttributes().size() ,this.getTableName().toString()),TLog.DEBUG,this.getTableName());
082        }
083        int c = 0;
084        for(TAttributeNode node:getAttributes()){
085            if (node.getSqlColumn() != null){
086                if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
087                    TBaseType.log(String.format("\tAttribute: <%s>, SQL column: <%s>",node.getName(), node.getSqlColumn()!=null?node.getSqlColumn().toString():"N/A" ),TLog.DEBUG);
088                }
089            }else{
090                if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
091                    TBaseType.log(String.format("\tAttribute: <%s>, Select list column: <%s>",node.getName(), node.getSubLevelResultColumn()!=null?node.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG);
092                }
093            }
094            if (node.getAccompaniedAttributeNodes().size() >0 ){
095                if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
096                    TBaseType.log(String.format("\t\tAccompanied nodes: %d",node.getAccompaniedAttributeNodes().size()),TLog.DEBUG);
097                }
098                for(TAttributeNode n:node.getAccompaniedAttributeNodes()){
099                    if (n.getSqlColumn() != null){
100                        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
101                            TBaseType.log(String.format("\t\tAttribute: <%s>, SQL column: <%s>",n.getName(), n.getSqlColumn()!=null?n.getSqlColumn().toString():"N/A" ),TLog.DEBUG);
102                        }
103                    }else{
104                        if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
105                            TBaseType.log(String.format("\t\tAttribute: <%s>, Select list column: <%s>",n.getName(), n.getSubLevelResultColumn()!=null?n.getSubLevelResultColumn().toString():"N/A" ),TLog.DEBUG);
106                        }
107                    }
108                }
109            }
110
111            c++;
112            if (c > TLog.OUTPUT_ATTRIBUTES_MAX){
113                if (TBaseType.DUMP_RESOLVER_LOG_TO_CONSOLE){
114                    TBaseType.log(String.format("\t...skipped after output %d attributes",c-1),TLog.DEBUG,this.getTableName().getStartToken());
115                }
116
117                break;
118            }
119        }
120    }
121
122    public String getRelationName(){
123        return this.getTableName().toString();
124    }
125
126//    public ArrayList<TAttributeNode> getAttributes(){
127//        return relationAttributes;
128//    }
129
130    private TSelectSqlNode selectNode;
131    private TSelectSqlStatement subquery;
132
133    private  TInsertSqlNode insertSqlNode;
134    private TInsertSqlStatement insertStmt;
135
136    private  TUpdateSqlNode updateSqlNode;
137    private TUpdateSqlStatement updateStmt;
138
139    private TDeleteSqlNode deleteSqlNode;
140    private TDeleteSqlStatement deleteStmt;
141
142    private TCustomSqlStatement preparableStmt;
143
144    public  boolean searchColumnInResultSet(TCustomSqlStatement pSql,TTable pTable,TObjectName pColumn,boolean pMustIn){
145      boolean lcResult = false;
146        if (getColumnList() != null){
147            for (int i=0;i<getColumnList().size();i++){
148                lcResult = getColumnList().getObjectName(i).toString().equalsIgnoreCase(pColumn.getColumnNameOnly());
149                //pColumn.setSourceColumn(getColumnList().getObjectName(i));
150                if (lcResult) break;
151            }
152            return lcResult;
153        }
154
155        TCustomSqlStatement lcStmt = pSql;
156        while (lcStmt != null){
157            if (lcStmt == getSubquery()){
158                pTable.getLinkedColumns().addObjectName(pColumn);
159                pColumn.setSourceTable(pTable);
160                lcResult = true;
161                break;
162            }
163            lcStmt = lcStmt.getParentStmt();
164        }
165
166        if (lcResult) return true;
167
168        if (getSubquery() == null) return false;
169        lcResult = getSubquery().searchColumnInResultSet(pColumn,pMustIn);
170
171        return lcResult;
172    }
173
174    /**
175     * preparable statement can be:
176     * <p> {@link #getSubquery()}
177     * <p> or{@link #getUpdateStmt()}
178     * <p> or{@link #getInsertStmt()}
179     * <p> or{@link #getDeleteStmt()}
180     * @return
181     */
182    public TCustomSqlStatement getPreparableStmt() {
183        preparableStmt = null;
184        if (subquery!=null){
185            preparableStmt = subquery;
186        }else if (updateStmt != null){
187            preparableStmt = updateStmt;
188        }else if (deleteStmt != null){
189            preparableStmt = deleteStmt;
190        }else if (insertStmt != null){
191            preparableStmt = insertStmt;
192        }
193
194        return preparableStmt;
195    }
196
197    public TUpdateSqlStatement getUpdateStmt() {
198        return updateStmt;
199    }
200
201    public TInsertSqlStatement getInsertStmt() {
202
203        return insertStmt;
204    }
205
206    public TDeleteSqlStatement getDeleteStmt() {
207
208        return deleteStmt;
209    }
210
211    /**
212     * @return table name of this common table expression.
213     */
214    public TObjectName getTableName() {
215        return tableName;
216    }
217
218    private TObjectName tableName;
219
220    public void setColumnList(TObjectNameList columnList) {
221        this.columnList = columnList;
222    }
223
224    /**
225     * fullselect of this common table expression.
226     * @return
227     */
228    public TSelectSqlStatement getSubquery() {
229        return subquery;
230    }
231
232    /**
233     * @return List of column name of this common table expression.
234
235     */
236    public TObjectNameList getColumnList() {
237        return columnList;
238    }
239
240    private TObjectNameList columnList = null;
241
242    public void init(Object arg1,Object arg2)
243    {
244       tableName = (TObjectName)arg1;
245       //tableName.parseTablename();
246       //tableName.setObjectType(TObjectName.ttobjTableCTE);
247       tableName.setDbObjectType(EDbObjectType.cte);
248
249       if (arg2 instanceof TSelectSqlNode){
250       selectNode = (TSelectSqlNode)arg2;
251       }else if (arg2 instanceof TInsertSqlNode){
252           insertSqlNode = (TInsertSqlNode)arg2;
253       }else if (arg2 instanceof TUpdateSqlNode){
254           updateSqlNode = (TUpdateSqlNode)arg2;
255       }else if (arg2 instanceof TDeleteSqlNode){
256           deleteSqlNode = (TDeleteSqlNode)arg2;
257       }
258    }
259
260    public void incParenthesisCount() {
261        if (selectNode != null){
262            selectNode.incParenthesisCount();
263        }
264    }
265
266    public void doParse(TCustomSqlStatement psql, ESqlClause plocation){
267
268        if (selectNode != null){
269            //long t = System.currentTimeMillis();
270            subquery = new TSelectSqlStatement(psql.dbvendor);
271            subquery.rootNode = selectNode;
272            subquery.setQueryOfCTE(true);
273            subquery.setCteIncludeThisStmt(this);
274            subquery.doParseStatement(psql);
275            for(TTable t:subquery.getRelations()){
276                if (t.isCTEName() && t.getCTE() == this){
277                   // System.out.println("found cte name in the same level:"+ t.getCTE().toString());
278                    t.setCTEName(false);
279                    t.setCTE(null);
280                }
281            }
282//            if (columnList == null){
283//                columnList = new TObjectNameList();
284//                for(TResultColumn resultColumn:subquery.getResultColumnList()){
285//                    columnList.addObjectName(new TObjectName());
286//
287//                }
288//            }
289            //System.out.println("Time Escaped: " + (System.currentTimeMillis() - t)+", sql size:"+ this.toString().length() );
290        }else if (insertSqlNode != null){
291            insertStmt = new TInsertSqlStatement(psql.dbvendor);
292            insertStmt.rootNode = insertSqlNode;
293            insertStmt.setCteIncludeThisStmt(this);
294            insertStmt.doParseStatement(psql);
295        }else if (deleteSqlNode != null){
296            deleteStmt = new TDeleteSqlStatement(psql.dbvendor);
297            deleteStmt.rootNode = deleteSqlNode;
298            deleteStmt.setCteIncludeThisStmt(this);
299            deleteStmt.doParseStatement(psql);
300        }else if (updateSqlNode != null){
301            updateStmt = new TUpdateSqlStatement(psql.dbvendor);
302            updateStmt.rootNode = updateSqlNode;
303            updateStmt.setCteIncludeThisStmt(this);
304            updateStmt.doParseStatement(psql);
305        }
306    }
307
308    public void accept(TParseTreeVisitor v){
309        v.preVisit(this);
310        v.postVisit(this);
311    }
312
313    public void acceptChildren(TParseTreeVisitor v){
314        v.preVisit(this);
315        if (subquery != null){
316            subquery.acceptChildren(v);
317        }
318        v.postVisit(this);
319    }
320
321    public void setSubquery(TSelectSqlStatement subquery) {
322        this.subquery = subquery;
323    }
324
325    public void setInsertStmt(TInsertSqlStatement insertStmt) {
326        this.insertStmt = insertStmt;
327    }
328
329    public void setUpdateStmt(TUpdateSqlStatement updateStmt) {
330        this.updateStmt = updateStmt;
331    }
332
333    public void setDeleteStmt(TDeleteSqlStatement deleteStmt) {
334        this.deleteStmt = deleteStmt;
335    }
336
337    public void setPreparableStmt(TCustomSqlStatement preparableStmt) {
338        this.preparableStmt = preparableStmt;
339    }
340
341    public void setTableName(TObjectName tableName) {
342        this.tableName = tableName;
343    }
344}