001package gudusoft.gsqlparser.stmt;
002
003import gudusoft.gsqlparser.*;
004import gudusoft.gsqlparser.nodes.*;
005import gudusoft.gsqlparser.nodes.couchbase.TUseKeyIndex;
006import gudusoft.gsqlparser.nodes.mssql.TOptionClause;
007import gudusoft.gsqlparser.nodes.oracle.TErrorLoggingClause;
008
009import java.util.ArrayList;
010
011/**
012 * SQL update statement.
013 * <br>
014 * <br> {@link #getTargetTable} returns the target table, this table can also be fetched from the first element of  {@link #tables}.
015 * <br> If there is a from clause in update statement, {@link #joins} returns all the tables in the from clause.
016 * <br> {@link #getResultColumnList()} returns assignment in set clause.
017 *
018 *<pre>
019 * UPDATE dbo.Table2
020 * SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
021 * FROM dbo.Table2
022 * INNER JOIN dbo.Table1
023 * ON (dbo.Table2.ColA = dbo.Table1.ColA);
024 *</pre>
025 * Table: dbo.Table2 can be fetched from {@link #getTargetTable} or {@link #tables}
026 * <br>set clause: dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB, {@link #getResultColumnList}
027 * <br>from clause: dbo.Table2 inner join , {@link #joins}
028 *
029 *
030 * @see TCustomSqlStatement#cteList
031 * @see TCustomSqlStatement#topClause
032 * @see TCustomSqlStatement#targetTable
033 * @see TCustomSqlStatement#outputClause
034 * @see TCustomSqlStatement#joins
035 * @see TCustomSqlStatement#resultColumnList 
036 * @see TCustomSqlStatement#whereClause
037 * @see TCustomSqlStatement#returningClause
038 */
039
040public class TUpdateSqlStatement extends TCustomSqlStatement {
041
042
043    private TInsertSqlStatement insertSqlStatement = null;
044
045    /**
046     * Teradata, insert statement used after ELSE keyword
047     * @return insert statement used after ELSE keyword
048     */
049    public TInsertSqlStatement getInsertSqlStatement() {
050        return insertSqlStatement;
051    }
052
053    private TErrorLoggingClause errorLoggingClause;
054
055    /**
056     * Oracle, error logging clause
057     * @return Oracle, error logging clause
058     */
059    public TErrorLoggingClause getErrorLoggingClause() {
060        return errorLoggingClause;
061    }
062
063    private TOptionClause optionClause;
064
065    /**
066     * sql server option clause
067     * @return option clause
068     *
069     * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause
070     */
071    public TOptionClause getOptionClause() {
072        return optionClause;
073    }
074
075    private TSourceToken updateToken = null;
076
077    public void setUpdateToken(TSourceToken updateToken) {
078        this.updateToken = updateToken;
079    }
080
081    /**
082     *  UPDATE keyword
083     *
084     * @return UPDATE keyword in update statement.
085     */
086    public TSourceToken getUpdateToken() {
087
088        return updateToken;
089    }
090
091    private TJoinList referenceJoins = null;
092
093    /**
094     * @deprecated As of v1.9.7.2, use {@link #joins} instead.
095     * <br>
096     * <p>  getReferenceJoins() represents: table_references
097     * @return table references in from clause
098     */
099    public TJoinList getReferenceJoins() {
100        if (this.referenceJoins == null){
101            this.referenceJoins = new TJoinList();
102        }
103        return referenceJoins;
104    }
105
106    private TOrderBy orderByClause = null;
107
108    /**
109     * Couchbase, MySQL limit clause.
110     * @return Couchbase, MySQL limit clause.
111     */
112    public TLimitClause getLimitClause() {
113        return limitClause;
114    }
115
116    /**
117     * Order by clause is not used.
118     * @return Order by clause
119     */
120    public TOrderBy getOrderByClause() {
121        return orderByClause;
122    }
123
124    private TLimitClause limitClause = null;
125
126    public TUpdateSqlStatement(EDbVendor dbvendor) {
127        super(dbvendor);
128        sqlstatementtype = ESqlStatementType.sstupdate;
129    }
130
131    void buildsql() {
132    }
133
134    void clear() {
135    }
136
137    String getasprettytext() {
138        return "";
139    }
140
141    void iterate(TVisitorAbs pvisitor) {
142    }
143
144    public int doParseStatement(TCustomSqlStatement psql) {
145        if (rootNode == null) return -1;
146        TUpdateSqlNode updateNode = (TUpdateSqlNode)rootNode;
147
148        if (this.sourcetokenlist.size() == 0){
149            // subquery nested in other statements.
150            this.setStartToken(updateNode.getStartToken());
151            this.setEndToken(updateNode.getEndToken());
152        }
153
154        super.doParseStatement(psql);
155        this.updateToken = updateNode.getUpdateToken();
156        
157        if (updateNode.cteList != null){
158            this.setCteList(updateNode.cteList);
159            this.getCteList().doParse(this, ESqlClause.cte);
160        }
161
162        if (updateNode.getTopClause() != null){
163           updateNode.getTopClause().doParse(this,ESqlClause.top);
164           this.setTopClause(updateNode.getTopClause());
165        }
166
167        if (updateNode.getSourceTableList() != null){ // update ... from source table list
168            TFromTable lcFromTable = null;
169            TJoin lcJoin = null;
170
171            for(int i=0; i<updateNode.getSourceTableList().size();i++){
172                lcFromTable = updateNode.getSourceTableList().getFromTable(i);
173                if (lcFromTable.getFromtableType() != ETableSource.join){
174                    lcJoin = new TJoin();
175                    TTable lcTable =  analyzeFromTable(lcFromTable,true);
176                    lcTable.setEffectType(ETableEffectType.tetSelect);
177                    lcJoin.setTable(lcTable);
178                    this.getRelations().add(lcTable);
179                }else{
180                    this.fromSourceJoin = lcFromTable.getJoinExpr();
181
182                    this.fromSourceTable = new TTable();
183                    this.fromSourceTable.setTableType(ETableSource.join);
184                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
185                    this.fromSourceTable.setStartToken(lcFromTable.getStartToken());
186                    this.fromSourceTable.setEndToken(lcFromTable.getEndToken());
187                    this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser());
188                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
189                    this.getRelations().add(this.fromSourceTable);
190
191                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
192                    lcJoin.doParse(this, ESqlClause.join);
193                }
194                joins.addJoin(lcJoin);
195            }
196        }
197
198        if (updateNode.getTargetTable().getFromtableType() != ETableSource.join ){
199            // search in from clause to see if this is the table alias of table in from clause
200            boolean isTableAlias = false;
201            TTable lcLinkTable = null;
202            if (getJoins().size() > 0){
203                for(int j=0;j<getJoins().size();j++){
204                    lcLinkTable = getJoins().getJoin(j).getTable();
205                    if (lcLinkTable != null){
206                        if (lcLinkTable.getAliasClause() != null){
207                            isTableAlias = updateNode.getTargetTable().toString().equalsIgnoreCase(lcLinkTable.getAliasName());
208                            if (isTableAlias) break;
209                        }
210                    }
211                }
212            }
213            TTable lcTable = analyzeFromTable(updateNode.getTargetTable(),false);
214            lcTable.setEffectType(ETableEffectType.tetUpdate);
215            if (isTableAlias){
216                lcTable.setLinkTable(lcLinkTable);
217                setTargetTable(lcLinkTable);
218            }else{
219                tables.insertElementAt(lcTable,0);
220                setTargetTable(lcTable);
221                this.getRelations().add(0,lcTable); // update table 需要放在 from table 前
222            }
223            //setTargetTable(lcTable);
224        }else{
225            this.fromSourceJoin = updateNode.getTargetTable().getJoinExpr();
226
227            this.fromSourceTable = new TTable();
228            this.fromSourceTable.setTableType(ETableSource.join);
229            this.fromSourceTable.setAliasClause(updateNode.getTargetTable().getJoinExpr().getAliasClause());
230            this.fromSourceTable.setStartToken(updateNode.getTargetTable().getJoinExpr().getStartToken());
231            this.fromSourceTable.setEndToken(updateNode.getTargetTable().getJoinExpr().getEndToken());
232            this.fromSourceTable.setGsqlparser(updateNode.getTargetTable().getJoinExpr().getGsqlparser());
233            this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
234            this.getRelations().add(0,this.fromSourceTable); // update table 需要放在 from table 前
235
236            TJoin  lcJoin1 = analyzeJoin(updateNode.getTargetTable().getJoinExpr(),null,true);
237            lcJoin1.doParse(this, ESqlClause.join);
238            setTargetTable(lcJoin1.getTable());
239            joins.addJoin(lcJoin1);
240        }
241
242        if (updateNode.getUseKeyIndex() != null){
243            setUseKeyIndex(updateNode.getUseKeyIndex());
244            getUseKeyIndex().doParse(this,ESqlClause.unknown);
245        }
246
247        if (updateNode.getOutputClause() != null){
248            updateNode.getOutputClause().doParse(this,ESqlClause.output);
249            this.setOutputClause(updateNode.getOutputClause());
250        }
251
252        setResultColumnList(updateNode.getResultColumnList());
253
254        if (updateNode.getUnSetTerms() != null){
255            setUnSetTerms(updateNode.getUnSetTerms());
256            getUnSetTerms().doParse(this,ESqlClause.unSet);
257        }
258
259
260        if (updateNode.getReferenceTableList() != null){
261            // Postgresql syntax:
262            // update table_name1 set f=1
263            // from table_references
264            TFromTable lcFromTable = null;
265            TJoin lcJoin = null;
266
267            for(int i=0; i<updateNode.getReferenceTableList().size();i++){
268                lcFromTable = updateNode.getReferenceTableList().getFromTable(i);
269                if (lcFromTable.getFromtableType() != ETableSource.join){
270                    lcJoin = new TJoin();
271                    TTable lcTable = analyzeFromTable(lcFromTable,true);
272                    lcTable.setEffectType(ETableEffectType.tetSelect);
273                    lcJoin.setTable( lcTable);
274                    this.getRelations().add(lcTable);
275                }else{
276                    this.fromSourceJoin = lcFromTable.getJoinExpr();
277
278                    this.fromSourceTable = new TTable();
279                    this.fromSourceTable.setTableType(ETableSource.join);
280                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
281                    this.fromSourceTable.setStartToken(lcFromTable.getJoinExpr().getStartToken());
282                    this.fromSourceTable.setEndToken(lcFromTable.getJoinExpr().getEndToken());
283                    this.fromSourceTable.setGsqlparser(lcFromTable.getJoinExpr().getGsqlparser());
284                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
285                    this.getRelations().add(this.fromSourceTable);
286
287                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
288                    lcJoin.doParse(this, ESqlClause.join);
289                }
290              //  this.getReferenceJoins().addJoin(lcJoin);
291                joins.addJoin(lcJoin);
292            }
293
294        }
295
296        if (getResultColumnList() != null){
297            getResultColumnList().doParse(this,ESqlClause.set);
298        }
299
300        if (updateNode.getOrderByClause() != null){
301            setOrderByClause(updateNode.getOrderByClause());
302            getOrderByClause().doParse(this,ESqlClause.orderby);
303        }
304
305        if (updateNode.getLimitClause() != null){
306            setLimitClause(updateNode.getLimitClause());
307            getLimitClause().doParse(this,ESqlClause.limit);
308        }
309
310        if (updateNode.getWhereCondition() != null){
311            updateNode.getWhereCondition().doParse(this,ESqlClause.where);
312            this.setWhereClause(updateNode.getWhereCondition());
313        }
314
315        if (updateNode.getReturningClause() != null){
316            updateNode.getReturningClause().doParse(this,ESqlClause.returning);
317            this.setReturningClause(updateNode.getReturningClause());
318        }
319
320        this.optionClause = updateNode.getOptionClause();
321
322        errorLoggingClause = updateNode.getErrorLoggingClause();
323
324        if (updateNode.getInsertSqlNode() != null){
325            insertSqlStatement = new TInsertSqlStatement(this.dbvendor);
326            insertSqlStatement.rootNode = updateNode.getInsertSqlNode();
327            insertSqlStatement.doParseStatement(this);
328
329        }
330
331        // remove table alias A from tables like this SQL:
332        // delete  A
333        // from  myTable A
334        // join otherTable B on A.Id=B.Id
335        int deletedTables[] = new int[this.tables.size()];
336        TTable lcTable = null,lcTable2 = null;
337        for(int i=0;i<this.tables.size();i++){
338            lcTable = this.tables.getTable(i);
339            if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){
340                for(int j=0;j<this.tables.size();j++){
341                    if (i == j) {continue;}
342                    lcTable2 = this.tables.getTable(j);
343                    if (lcTable2.getAliasClause() != null){
344                        if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){
345                            deletedTables[i] = 1;
346                            //lcTable.setLinkTable(true);
347                            lcTable.setLinkTable(lcTable2);
348//                            for(int k=0;k<lcTable.getObjectNameReferences().size();k++){
349//                                lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
350//                                //lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
351//                                //lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2);
352//                               // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString());
353//                            }
354                        }
355                    }
356
357                }
358            }
359        }
360//        for(int i = this.tables.size()-1;i>=0;i--){
361//            if (deletedTables[i] == 1){
362//                //this.tables.removeElementAt(i);
363//            }
364//        }
365        
366        return 0;
367    }
368
369    public void accept(TParseTreeVisitor v){
370        v.preVisit(this);
371        v.postVisit(this);
372    }
373
374    public void acceptChildren(TParseTreeVisitor v){
375        v.preVisit(this);
376
377        if (this.getCteList() != null){
378            this.getCteList().acceptChildren(v);
379        }
380
381
382
383        if (TBaseType.USE_JOINEXPR_INSTEAD_OF_JOIN){
384
385            for(TTable table:getRelations()){
386                table.acceptChildren(v);
387            }
388
389        }else{
390            this.getTargetTable().acceptChildren(v);
391            if (this.joins.size() > 0){
392                this.joins.acceptChildren(v);
393            }
394        }
395
396        if (this.getTopClause() != null){
397            this.getTopClause().acceptChildren(v);
398        }
399
400        if (this.getOutputClause() != null){
401            this.getOutputClause().acceptChildren(v);
402        }
403
404        if (this.getResultColumnList() != null){
405            this.getResultColumnList().acceptChildren(v);
406        }else{
407            TBaseType.log("set clause in update stmt is null",TLog.WARNING);
408        }
409
410
411        if (this.getWhereClause() != null){
412            this.getWhereClause().acceptChildren(v);
413        }
414
415        if (this.getOrderByClause() != null){
416            this.getOrderByClause().acceptChildren(v);
417        }
418
419        if (this.getLimitClause() != null){
420            this.getLimitClause().acceptChildren(v);
421        }
422
423        if (this.getReturningClause() != null){
424            this.getReturningClause().acceptChildren(v);
425        }
426
427        v.postVisit(this);
428    }
429
430    public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) {
431        this.errorLoggingClause = errorLoggingClause;
432    }
433
434    public void setOptionClause(TOptionClause optionClause) {
435        this.optionClause = optionClause;
436    }
437
438    public void setReferenceJoins(TJoinList referenceJoins) {
439        this.referenceJoins = referenceJoins;
440    }
441
442    public void setOrderByClause(TOrderBy orderByClause) {
443        this.orderByClause = orderByClause;
444    }
445
446    public void setLimitClause(TLimitClause limitClause) {
447        this.limitClause = limitClause;
448    }
449
450    private TUseKeyIndex useKeyIndex;//couchbase
451
452    public void setUseKeyIndex(TUseKeyIndex useKeyIndex) {
453        this.useKeyIndex = useKeyIndex;
454    }
455
456    public TUseKeyIndex getUseKeyIndex() {
457
458        return useKeyIndex;
459    }
460
461    private TResultColumnList unSetTerms; //couchbase
462
463    public void setUnSetTerms(TResultColumnList unSetTerms) {
464        this.unSetTerms = unSetTerms;
465    }
466
467    /**
468     * Couchbase unset clause
469     * @return Couchbase unset clause
470     */
471    public TResultColumnList getUnSetTerms() {
472
473        return unSetTerms;
474    }
475
476}