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 *
013 * SQL delete statement.
014 * <br>
015 * <br>{@link #getTargetTable} returns the target table of delete statement, this table also stored in the first element of {@link #tables}.
016 * <br>MySQL may contains multiple target tables, please fetch those tables from {@link #joins}.
017 * <br>If there is a FROM clause in the delete statement, all those tables in the from clause can be fetched from {@link #getReferenceJoins}.
018 * <br>
019 *  <pre>
020 *   DELETE FROM Production.ProductCostHistory
021 *   WHERE StandardCost &gt; 1000.00;
022 *  </pre>
023 * <p>  Production.ProductCostHistory can be fetched from {@link #getTargetTable} or {@link #tables}
024 * <pre>
025 *  DELETE FROM Sales.SalesPersonQuotaHistory
026 *  FROM Sales.SalesPersonQuotaHistory AS spqh
027 *  INNER JOIN Sales.SalesPerson AS sp
028 *  ON spqh.BusinessEntityID = sp.BusinessEntityID
029 *  WHERE sp.SalesYTD &gt; 2500000.00;
030 * </pre>
031 *
032 * Sales.SalesPersonQuotaHistory AS spqh should be fetched froom {@link #getReferenceJoins}
033 *
034 * @see TCustomSqlStatement#cteList
035 * @see TCustomSqlStatement#topClause
036 * @see TCustomSqlStatement#targetTable
037 * @see TCustomSqlStatement#joins
038 * @see TCustomSqlStatement#whereClause
039 * @see TCustomSqlStatement#returningClause
040 * @see TCustomSqlStatement#outputClause
041 */
042public class TDeleteSqlStatement extends TCustomSqlStatement  {
043
044//    public ArrayList<TObjectName> getReferenceAttributes(){
045//        return null;
046//    }
047
048//    @Override
049//    public ArrayList<TAttributeNode> getAttributes(){
050//        if (relationAttributes.size() != 0) return relationAttributes;
051//
052//        for(TTable table:getTables()){
053//            relationAttributes.addAll(table.getAttributes());
054//        }
055//
056//        return relationAttributes;
057//    }
058
059
060    private boolean fromKeyword = false;
061
062    public void setFromKeyword(boolean fromKeyword) {
063        this.fromKeyword = fromKeyword;
064    }
065
066    /**
067     * Whether FROM keyword is used.
068     *
069     * @return true if FROM keyword is used after delete.
070     */
071    public boolean isFromKeyword() {
072
073        return fromKeyword;
074    }
075
076    private TErrorLoggingClause errorLoggingClause;
077
078    /**
079     * Oracle error logging clause
080     * @return Oracle error logging clause
081     */
082    public TErrorLoggingClause getErrorLoggingClause() {
083        return errorLoggingClause;
084    }
085
086    private TOptionClause optionClause;
087
088    /**
089     * sql server option clause
090     * @return {@link TOptionClause option clause}
091     *
092     * @see gudusoft.gsqlparser.nodes.mssql.TOptionClause
093     */
094    public TOptionClause getOptionClause() {
095        return optionClause;
096    }
097
098    private TSourceToken deleteToken = null;
099
100    public void setDeleteToken(TSourceToken deleteToken) {
101        this.deleteToken = deleteToken;
102    }
103
104    /**
105     * DELETE keyword of the delete statement.
106     * @return DELETE token in delete statement.
107     */
108    public TSourceToken getDeleteToken() {
109
110        return deleteToken;
111    }
112
113    private TOrderBy orderByClause = null;
114
115    /**
116     * MySQL order by clause.
117     * @return MySQL order by clause.
118     */
119    public TOrderBy getOrderByClause() {
120
121        return orderByClause;
122    }
123
124    private TLimitClause limitClause = null;
125
126
127    /**
128     * MySQL limit clause.
129     * @return MySQL limit clause.
130     */
131    public TLimitClause getLimitClause() {
132
133        return limitClause;
134    }
135
136    private TJoinList referenceJoins = null;
137
138    /**
139     * If there is a FROM clause in delete statement, this method returns the list of join table in the from clause.
140     * @return list of {@link gudusoft.gsqlparser.nodes.TJoin}
141     */
142    public TJoinList getReferenceJoins() {
143        if (this.referenceJoins == null){
144            this.referenceJoins = new TJoinList();
145        }
146        return referenceJoins;
147    }
148
149    public TDeleteSqlStatement(EDbVendor dbvendor) {
150        super(dbvendor);
151        sqlstatementtype = ESqlStatementType.sstdelete;
152    }
153
154    void buildsql() {
155    }
156
157    void clear() {
158    }
159
160    String getasprettytext() {
161        return "";
162    }
163
164    void iterate(TVisitorAbs pvisitor) {
165    }
166
167    /**
168     * Used internal.
169     *
170     * @param psql input sql.
171     * @return zero if no syntax error detected.
172     */
173    public int doParseStatement(TCustomSqlStatement psql) {
174        if (rootNode == null) return -1;
175        TDeleteSqlNode deleteNode = (TDeleteSqlNode)rootNode;
176
177        this.fromKeyword = deleteNode.isFromKeyword();
178
179        if (this.sourcetokenlist.size() == 0){
180            // subquery nested in other statements.
181            this.setStartToken(deleteNode.getStartToken());
182            this.setEndToken(deleteNode.getEndToken());
183        }
184
185        super.doParseStatement(psql);
186        this.deleteToken = deleteNode.getDeleteToken();
187
188        if (deleteNode.cteList != null){
189            this.setCteList( deleteNode.cteList);
190            this.getCteList().doParse(this, ESqlClause.cte);
191        }
192
193        if (deleteNode.getTopClause() != null){
194           deleteNode.getTopClause().doParse(this,ESqlClause.top);
195           this.setTopClause(deleteNode.getTopClause());
196        }
197
198        TTable lcTable1 = analyzeFromTable(deleteNode.getTargetTable(),true);
199        lcTable1.setEffectType(ETableEffectType.tetDelete);
200        setTargetTable(lcTable1);
201        this.getRelations().add(lcTable1);
202
203        if (deleteNode.getSourceTableList() != null){
204            TFromTable lcFromTable = null;
205            TJoin lcJoin = null;
206
207            for(int i=0; i<deleteNode.getSourceTableList().size();i++){
208                 lcFromTable = deleteNode.getSourceTableList().getFromTable(i);
209                if (lcFromTable.getFromtableType() != ETableSource.join){
210                    lcJoin = new TJoin();
211                    lcTable1 = analyzeFromTable(lcFromTable,true);
212                    lcTable1.setEffectType(ETableEffectType.tetSelect);
213                    lcJoin.setTable(lcTable1);
214                    this.getRelations().add(lcTable1);
215                }else{
216                    this.fromSourceJoin = lcFromTable.getJoinExpr();
217
218                    this.fromSourceTable = new TTable();
219                    this.fromSourceTable.setTableType(ETableSource.join);
220                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
221                    this.fromSourceTable.setStartToken(lcFromTable.getStartToken());
222                    this.fromSourceTable.setEndToken(lcFromTable.getEndToken());
223                    this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser());
224                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
225                    this.getRelations().add(this.fromSourceTable);
226
227                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
228                    lcJoin.doParse(this, ESqlClause.join);
229                }
230                joins.addJoin(lcJoin);
231            }
232        }
233
234        if (deleteNode.getReferenceTableList() != null){
235            // MySQL syntax:
236            // delete table_name1.[*],table_name2.[*] ...
237            // from table_references
238            TFromTable lcFromTable = null;
239            TJoin lcJoin = null;
240
241            for(int i=0; i<deleteNode.getReferenceTableList().size();i++){
242                lcFromTable = deleteNode.getReferenceTableList().getFromTable(i);
243                if (lcFromTable.getFromtableType() != ETableSource.join){
244                    lcJoin = new TJoin();
245                    lcTable1 = analyzeFromTable(lcFromTable,true);
246                    lcJoin.setTable( lcTable1);
247                    this.getRelations().add(lcTable1);
248                }else{
249                    this.fromSourceJoin = lcFromTable.getJoinExpr();
250
251                    this.fromSourceTable = new TTable();
252                    this.fromSourceTable.setTableType(ETableSource.join);
253                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
254                    this.fromSourceTable.setStartToken(lcFromTable.getStartToken());
255                    this.fromSourceTable.setEndToken(lcFromTable.getEndToken());
256                    this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser());
257                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
258                    this.getRelations().add(this.fromSourceTable);
259
260                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
261                    lcJoin.doParse(this, ESqlClause.join);
262                }
263                this.getReferenceJoins().addJoin(lcJoin);
264            }
265
266        }
267
268        if (deleteNode.getOutputClause() != null){
269            deleteNode.getOutputClause().doParse(this,ESqlClause.output);
270            this.setOutputClause(deleteNode.getOutputClause());
271        }
272
273        if (deleteNode.getWhereCondition() != null){
274            deleteNode.getWhereCondition().doParse(this,ESqlClause.where);
275            this.setWhereClause(deleteNode.getWhereCondition());
276        }
277
278        if (deleteNode.getReturningClause() != null){
279            deleteNode.getReturningClause().doParse(this,ESqlClause.returning);
280            this.setReturningClause(deleteNode.getReturningClause());
281        }
282
283        this.orderByClause = deleteNode.getOrderByClause();
284        if (this.orderByClause != null){
285            this.orderByClause.doParse(this,ESqlClause.orderby);
286        }
287
288        this.limitClause = deleteNode.getLimitClause();
289        if (this.limitClause != null){
290            this.limitClause.doParse(this,ESqlClause.limit);
291        }
292
293        this.optionClause = deleteNode.getOptionClause();
294
295        errorLoggingClause = deleteNode.getErrorLoggingClause();
296
297        // remove table alias A from tables like this SQL:
298        // delete  A
299        // from  myTable A
300        // join otherTable B on A.Id=B.Id
301        int deletedTables[] = new int[this.tables.size()];
302        TTable lcTable = null,lcTable2 = null;
303        for(int i=0;i<this.tables.size();i++){
304            lcTable = this.tables.getTable(i);
305            if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){
306                for(int j=0;j<this.tables.size();j++){
307                    if (i == j) {continue;}
308                    lcTable2 = this.tables.getTable(j);
309                    if (lcTable2.getAliasClause() != null){
310                        if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){
311                            deletedTables[i] = 1;
312                            for(int k=0;k<lcTable.getObjectNameReferences().size();k++){
313                                lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
314                                lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
315                                lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2);
316                               // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString());
317                            }
318                            if (lcTable == getTargetTable()){
319                                setTargetTable(lcTable2);
320                            }
321                        }
322                    }
323
324                }
325            }
326        }
327        for(int i = this.tables.size()-1;i>=0;i--){
328            if (deletedTables[i] == 1){
329                this.tables.removeElementWithoutSyncTokens(i);
330            }
331        }
332
333        //couchbase
334        useKeyIndex = deleteNode.getUseKeyIndex();
335
336
337        return 0;
338    }
339
340    public void accept(TParseTreeVisitor v){
341        v.preVisit(this);
342        v.postVisit(this);
343    }
344
345    public void acceptChildren(TParseTreeVisitor v){
346        v.preVisit(this);
347
348        if (this.getCteList() != null){
349            this.getCteList().acceptChildren(v);
350        }
351
352        if (this.getTopClause() != null){
353            this.getTopClause().acceptChildren(v);
354        }
355
356        this.getTargetTable().acceptChildren(v);
357        if (this.joins.size() > 0){
358            this.joins.acceptChildren(v);
359        }
360
361        if (this.getOutputClause() != null){
362            this.getOutputClause().acceptChildren(v);
363        }
364
365        if (this.getWhereClause() != null){
366            this.getWhereClause().acceptChildren(v);
367        }
368
369        if (this.getReturningClause() != null){
370            this.getReturningClause().acceptChildren(v);
371        }
372
373        v.postVisit(this);
374    }
375
376    public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) {
377        this.errorLoggingClause = errorLoggingClause;
378    }
379
380    public void setOptionClause(TOptionClause optionClause) {
381        this.optionClause = optionClause;
382    }
383
384    public void setOrderByClause(TOrderBy orderByClause) {
385        this.orderByClause = orderByClause;
386    }
387
388    public void setLimitClause(TLimitClause limitClause) {
389        this.limitClause = limitClause;
390    }
391
392    public void setReferenceJoins(TJoinList referenceJoins) {
393        this.referenceJoins = referenceJoins;
394    }
395
396    //couchbase
397    private TUseKeyIndex useKeyIndex;
398
399    public void setUseKeyIndex(TUseKeyIndex useKeyIndex) {
400        this.useKeyIndex = useKeyIndex;
401    }
402
403    /**
404     * Couchbase use key index
405     * @return use key index
406     */
407    public TUseKeyIndex getUseKeyIndex() {
408
409        return useKeyIndex;
410    }
411
412
413}