1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.command.dml; |
7 | |
8 | import org.h2.api.Trigger; |
9 | import org.h2.command.CommandInterface; |
10 | import org.h2.command.Prepared; |
11 | import org.h2.engine.Right; |
12 | import org.h2.engine.Session; |
13 | import org.h2.engine.UndoLogRecord; |
14 | import org.h2.expression.Expression; |
15 | import org.h2.result.ResultInterface; |
16 | import org.h2.result.Row; |
17 | import org.h2.result.RowList; |
18 | import org.h2.table.PlanItem; |
19 | import org.h2.table.Table; |
20 | import org.h2.table.TableFilter; |
21 | import org.h2.util.StringUtils; |
22 | import org.h2.value.Value; |
23 | import org.h2.value.ValueNull; |
24 | |
25 | /** |
26 | * This class represents the statement |
27 | * DELETE |
28 | */ |
29 | public class Delete extends Prepared { |
30 | |
31 | private Expression condition; |
32 | private TableFilter tableFilter; |
33 | |
34 | /** |
35 | * The limit expression as specified in the LIMIT or TOP clause. |
36 | */ |
37 | private Expression limitExpr; |
38 | |
39 | public Delete(Session session) { |
40 | super(session); |
41 | } |
42 | |
43 | public void setTableFilter(TableFilter tableFilter) { |
44 | this.tableFilter = tableFilter; |
45 | } |
46 | |
47 | public void setCondition(Expression condition) { |
48 | this.condition = condition; |
49 | } |
50 | |
51 | @Override |
52 | public int update() { |
53 | tableFilter.startQuery(session); |
54 | tableFilter.reset(); |
55 | Table table = tableFilter.getTable(); |
56 | session.getUser().checkRight(table, Right.DELETE); |
57 | table.fire(session, Trigger.DELETE, true); |
58 | table.lock(session, true, false); |
59 | RowList rows = new RowList(session); |
60 | int limitRows = -1; |
61 | if (limitExpr != null) { |
62 | Value v = limitExpr.getValue(session); |
63 | if (v != ValueNull.INSTANCE) { |
64 | limitRows = v.getInt(); |
65 | } |
66 | } |
67 | try { |
68 | setCurrentRowNumber(0); |
69 | int count = 0; |
70 | while (limitRows != 0 && tableFilter.next()) { |
71 | setCurrentRowNumber(rows.size() + 1); |
72 | if (condition == null || Boolean.TRUE.equals( |
73 | condition.getBooleanValue(session))) { |
74 | Row row = tableFilter.get(); |
75 | boolean done = false; |
76 | if (table.fireRow()) { |
77 | done = table.fireBeforeRow(session, row, null); |
78 | } |
79 | if (!done) { |
80 | rows.add(row); |
81 | } |
82 | count++; |
83 | if (limitRows >= 0 && count >= limitRows) { |
84 | break; |
85 | } |
86 | } |
87 | } |
88 | int rowScanCount = 0; |
89 | for (rows.reset(); rows.hasNext();) { |
90 | if ((++rowScanCount & 127) == 0) { |
91 | checkCanceled(); |
92 | } |
93 | Row row = rows.next(); |
94 | table.removeRow(session, row); |
95 | session.log(table, UndoLogRecord.DELETE, row); |
96 | } |
97 | if (table.fireRow()) { |
98 | for (rows.reset(); rows.hasNext();) { |
99 | Row row = rows.next(); |
100 | table.fireAfterRow(session, row, null, false); |
101 | } |
102 | } |
103 | table.fire(session, Trigger.DELETE, false); |
104 | return count; |
105 | } finally { |
106 | rows.close(); |
107 | } |
108 | } |
109 | |
110 | @Override |
111 | public String getPlanSQL() { |
112 | StringBuilder buff = new StringBuilder(); |
113 | buff.append("DELETE "); |
114 | buff.append("FROM ").append(tableFilter.getPlanSQL(false)); |
115 | if (condition != null) { |
116 | buff.append("\nWHERE ").append(StringUtils.unEnclose( |
117 | condition.getSQL())); |
118 | } |
119 | if (limitExpr != null) { |
120 | buff.append("\nLIMIT (").append(StringUtils.unEnclose( |
121 | limitExpr.getSQL())).append(')'); |
122 | } |
123 | return buff.toString(); |
124 | } |
125 | |
126 | @Override |
127 | public void prepare() { |
128 | if (condition != null) { |
129 | condition.mapColumns(tableFilter, 0); |
130 | condition = condition.optimize(session); |
131 | condition.createIndexConditions(session, tableFilter); |
132 | } |
133 | PlanItem item = tableFilter.getBestPlanItem(session, 1); |
134 | tableFilter.setPlanItem(item); |
135 | tableFilter.prepare(); |
136 | } |
137 | |
138 | @Override |
139 | public boolean isTransactional() { |
140 | return true; |
141 | } |
142 | |
143 | @Override |
144 | public ResultInterface queryMeta() { |
145 | return null; |
146 | } |
147 | |
148 | @Override |
149 | public int getType() { |
150 | return CommandInterface.DELETE; |
151 | } |
152 | |
153 | public void setLimit(Expression limit) { |
154 | this.limitExpr = limit; |
155 | } |
156 | |
157 | @Override |
158 | public boolean isCacheable() { |
159 | return true; |
160 | } |
161 | |
162 | } |