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        unbindCteTarget(lcTable1);
201        setTargetTable(lcTable1);
202        this.getRelations().add(lcTable1);
203
204        if (deleteNode.getSourceTableList() != null){
205            TFromTable lcFromTable = null;
206            TJoin lcJoin = null;
207
208            for(int i=0; i<deleteNode.getSourceTableList().size();i++){
209                 lcFromTable = deleteNode.getSourceTableList().getFromTable(i);
210                if (lcFromTable.getFromtableType() != ETableSource.join){
211                    lcJoin = new TJoin();
212                    lcTable1 = analyzeFromTable(lcFromTable,true);
213                    lcTable1.setEffectType(ETableEffectType.tetSelect);
214                    lcJoin.setTable(lcTable1);
215                    this.getRelations().add(lcTable1);
216                }else{
217                    this.fromSourceJoin = lcFromTable.getJoinExpr();
218
219                    this.fromSourceTable = new TTable();
220                    this.fromSourceTable.setTableType(ETableSource.join);
221                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
222                    this.fromSourceTable.setStartToken(lcFromTable.getStartToken());
223                    this.fromSourceTable.setEndToken(lcFromTable.getEndToken());
224                    this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser());
225                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
226                    this.getRelations().add(this.fromSourceTable);
227
228                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
229                    lcJoin.doParse(this, ESqlClause.join);
230                }
231                joins.addJoin(lcJoin);
232            }
233        }
234
235        if (deleteNode.getReferenceTableList() != null){
236            // MySQL syntax:
237            // delete table_name1.[*],table_name2.[*] ...
238            // from table_references
239            TFromTable lcFromTable = null;
240            TJoin lcJoin = null;
241
242            for(int i=0; i<deleteNode.getReferenceTableList().size();i++){
243                lcFromTable = deleteNode.getReferenceTableList().getFromTable(i);
244                if (lcFromTable.getFromtableType() != ETableSource.join){
245                    lcJoin = new TJoin();
246                    lcTable1 = analyzeFromTable(lcFromTable,true);
247                    lcJoin.setTable( lcTable1);
248                    this.getRelations().add(lcTable1);
249                }else{
250                    this.fromSourceJoin = lcFromTable.getJoinExpr();
251
252                    this.fromSourceTable = new TTable();
253                    this.fromSourceTable.setTableType(ETableSource.join);
254                    this.fromSourceTable.setAliasClause(lcFromTable.getJoinExpr().getAliasClause());
255                    this.fromSourceTable.setStartToken(lcFromTable.getStartToken());
256                    this.fromSourceTable.setEndToken(lcFromTable.getEndToken());
257                    this.fromSourceTable.setGsqlparser(lcFromTable.getGsqlparser());
258                    this.fromSourceTable.setJoinExpr(this.fromSourceJoin);
259                    this.getRelations().add(this.fromSourceTable);
260
261                    lcJoin = analyzeJoin(lcFromTable.getJoinExpr(),null,true);
262                    lcJoin.doParse(this, ESqlClause.join);
263                }
264                this.getReferenceJoins().addJoin(lcJoin);
265            }
266
267        }
268
269        if (deleteNode.getOutputClause() != null){
270            deleteNode.getOutputClause().doParse(this,ESqlClause.output);
271            this.setOutputClause(deleteNode.getOutputClause());
272        }
273
274        if (deleteNode.getWhereCondition() != null){
275            deleteNode.getWhereCondition().doParse(this,ESqlClause.where);
276            this.setWhereClause(deleteNode.getWhereCondition());
277        }
278
279        if (deleteNode.getReturningClause() != null){
280            deleteNode.getReturningClause().doParse(this,ESqlClause.returning);
281            this.setReturningClause(deleteNode.getReturningClause());
282        }
283
284        this.orderByClause = deleteNode.getOrderByClause();
285        if (this.orderByClause != null){
286            this.orderByClause.doParse(this,ESqlClause.orderby);
287        }
288
289        this.limitClause = deleteNode.getLimitClause();
290        if (this.limitClause != null){
291            this.limitClause.doParse(this,ESqlClause.limit);
292        }
293
294        this.optionClause = deleteNode.getOptionClause();
295
296        errorLoggingClause = deleteNode.getErrorLoggingClause();
297
298        // remove table alias A from tables like this SQL:
299        // delete  A
300        // from  myTable A
301        // join otherTable B on A.Id=B.Id
302        int deletedTables[] = new int[this.tables.size()];
303        TTable lcTable = null,lcTable2 = null;
304        for(int i=0;i<this.tables.size();i++){
305            lcTable = this.tables.getTable(i);
306            if ((lcTable.getAliasClause() == null)&&(lcTable.isBaseTable())){
307                for(int j=0;j<this.tables.size();j++){
308                    if (i == j) {continue;}
309                    lcTable2 = this.tables.getTable(j);
310                    if (lcTable2.getAliasClause() != null){
311                        if (lcTable2.getAliasClause().toString().compareToIgnoreCase(lcTable.toString()) == 0){
312                            deletedTables[i] = 1;
313                            for(int k=0;k<lcTable.getObjectNameReferences().size();k++){
314                                lcTable2.getObjectNameReferences().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
315                                lcTable2.getLinkedColumns().addObjectName(lcTable.getObjectNameReferences().getObjectName(k));
316                                lcTable.getObjectNameReferences().getObjectName(k).setSourceTable(lcTable2);
317                               // System.out.println(lcTable.getObjectNameReferences().getAliasName(k).toString());
318                            }
319                            if (lcTable == getTargetTable()){
320                                setTargetTable(lcTable2);
321                            }
322                        }
323                    }
324
325                }
326            }
327        }
328        for(int i = this.tables.size()-1;i>=0;i--){
329            if (deletedTables[i] == 1){
330                this.tables.removeElementWithoutSyncTokens(i);
331            }
332        }
333
334        //couchbase
335        useKeyIndex = deleteNode.getUseKeyIndex();
336
337
338        return 0;
339    }
340
341    public void accept(TParseTreeVisitor v){
342        v.preVisit(this);
343        v.postVisit(this);
344    }
345
346    public void acceptChildren(TParseTreeVisitor v){
347        v.preVisit(this);
348
349        if (this.getCteList() != null){
350            this.getCteList().acceptChildren(v);
351        }
352
353        if (this.getTopClause() != null){
354            this.getTopClause().acceptChildren(v);
355        }
356
357        if (this.getTargetTable() != null){
358            this.getTargetTable().acceptChildren(v);
359        }
360        if (this.joins.size() > 0){
361            this.joins.acceptChildren(v);
362        }
363
364        if (this.getOutputClause() != null){
365            this.getOutputClause().acceptChildren(v);
366        }
367
368        if (this.getWhereClause() != null){
369            this.getWhereClause().acceptChildren(v);
370        }
371
372        if (this.getReturningClause() != null){
373            this.getReturningClause().acceptChildren(v);
374        }
375
376        v.postVisit(this);
377    }
378
379    public void setErrorLoggingClause(TErrorLoggingClause errorLoggingClause) {
380        this.errorLoggingClause = errorLoggingClause;
381    }
382
383    public void setOptionClause(TOptionClause optionClause) {
384        this.optionClause = optionClause;
385    }
386
387    public void setOrderByClause(TOrderBy orderByClause) {
388        this.orderByClause = orderByClause;
389    }
390
391    public void setLimitClause(TLimitClause limitClause) {
392        this.limitClause = limitClause;
393    }
394
395    public void setReferenceJoins(TJoinList referenceJoins) {
396        this.referenceJoins = referenceJoins;
397    }
398
399    //couchbase
400    private TUseKeyIndex useKeyIndex;
401
402    public void setUseKeyIndex(TUseKeyIndex useKeyIndex) {
403        this.useKeyIndex = useKeyIndex;
404    }
405
406    /**
407     * Couchbase use key index
408     * @return use key index
409     */
410    public TUseKeyIndex getUseKeyIndex() {
411
412        return useKeyIndex;
413    }
414
415
416}