File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\command\dml\Update.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.command.dml;
8
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import org.h2.api.Trigger;
12 import org.h2.command.CommandInterface;
13 import org.h2.command.Prepared;
14 import org.h2.constant.ErrorCode;
15 import org.h2.engine.Right;
16 import org.h2.engine.Session;
17 import org.h2.expression.Expression;
18 import org.h2.expression.Parameter;
19 import org.h2.expression.ValueExpression;
20 import org.h2.message.DbException;
21 import org.h2.result.ResultInterface;
22 import org.h2.result.Row;
23 import org.h2.result.RowList;
24 import org.h2.table.Column;
25 import org.h2.table.PlanItem;
26 import org.h2.table.Table;
27 import org.h2.table.TableFilter;
28 import org.h2.util.New;
29 import org.h2.util.StatementBuilder;
30 import org.h2.util.StringUtils;
31 import org.h2.value.Value;
32 import org.h2.value.ValueNull;
33
34 /**
35 * This class represents the statement
36 * UPDATE
37 */
38 public class Update extends Prepared {
39
40 private Expression condition;
41 private TableFilter tableFilter;
42
43 /** The limit expression as specified in the LIMIT clause. */
44 private Expression limitExpr;
45
46 private final ArrayList<Column> columns = New.arrayList();
47 private final HashMap<Column, Expression> expressionMap = New.hashMap();
48
49 public Update(Session session) {
50 super(session);
51 }
52
53 public void setTableFilter(TableFilter tableFilter) {
54 this.tableFilter = tableFilter;
55 }
56
57 public void setCondition(Expression condition) {
58 this.condition = condition;
59 }
60
61 /**
62 * Add an assignment of the form column = expression.
63 *
64 * @param column the column
65 * @param expression the expression
66 */
67 public void setAssignment(Column column, Expression expression) {
68 if (expressionMap.containsKey(column)) {
69 throw DbException.get(ErrorCode.DUPLICATE_COLUMN_NAME_1, column
70 .getName());
71 }
72 columns.add(column);
73 expressionMap.put(column, expression);
74 if (expression instanceof Parameter) {
75 Parameter p = (Parameter) expression;
76 p.setColumn(column);
77 }
78 }
79
80 public int update() {
81 tableFilter.startQuery(session);
82 tableFilter.reset();
83 RowList rows = new RowList(session);
84 try {
85 Table table = tableFilter.getTable();
86 session.getUser().checkRight(table, Right.UPDATE);
87 table.fire(session, Trigger.UPDATE, true);
88 table.lock(session, true, false);
89 int columnCount = table.getColumns().length;
90 // get the old rows, compute the new rows
91 setCurrentRowNumber(0);
92 int count = 0;
93 Column[] columns = table.getColumns();
94 int limitRows = -1;
95 if (limitExpr != null) {
96 Value v = limitExpr.getValue(session);
97 if (v != ValueNull.INSTANCE) {
98 limitRows = v.getInt();
99 }
100 }
101 while (tableFilter.next()) {
102 setCurrentRowNumber(count+1);
103 if (limitRows >= 0 && count >= limitRows) {
104 break;
105 }
106 if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) {
107 Row oldRow = tableFilter.get();
108 Row newRow = table.getTemplateRow();
109 for (int i = 0; i < columnCount; i++) {
110 Expression newExpr = expressionMap.get(columns[i]);
111 Value newValue;
112 if (newExpr == null) {
113 newValue = oldRow.getValue(i);
114 } else if (newExpr == ValueExpression.getDefault()) {
115 Column column = table.getColumn(i);
116 newValue = table.getDefaultValue(session, column);
117 } else {
118 Column column = table.getColumn(i);
119 newValue = column.convert(newExpr.getValue(session));
120 }
121 newRow.setValue(i, newValue);
122 }
123 table.validateConvertUpdateSequence(session, newRow);
124 boolean done = false;
125 if (table.fireRow()) {
126 done = table.fireBeforeRow(session, oldRow, newRow);
127 }
128 if (!done) {
129 rows.add(oldRow);
130 rows.add(newRow);
131 }
132 count++;
133 }
134 }
135 // TODO self referencing referential integrity constraints
136 // don't work if update is multi-row and 'inversed' the condition!
137 // probably need multi-row triggers with 'deleted' and 'inserted'
138 // at the same time. anyway good for sql compatibility
139 // TODO update in-place (but if the key changes,
140 // we need to update all indexes) before row triggers
141
142 // the cached row is already updated - we need the old values
143 table.updateRows(this, session, rows);
144 if (table.fireRow()) {
145 rows.invalidateCache();
146 for (rows.reset(); rows.hasNext();) {
147 Row o = rows.next();
148 Row n = rows.next();
149 table.fireAfterRow(session, o, n, false);
150 }
151 }
152 table.fire(session, Trigger.UPDATE, false);
153 return count;
154 } finally {
155 rows.close();
156 }
157 }
158
159 public String getPlanSQL() {
160 StatementBuilder buff = new StatementBuilder("UPDATE ");
161 buff.append(tableFilter.getPlanSQL(false)).append("\nSET\n ");
162 for (int i = 0, size = columns.size(); i < size; i++) {
163 Column c = columns.get(i);
164 Expression e = expressionMap.get(c);
165 buff.appendExceptFirst(",\n ");
166 buff.append(c.getName()).append(" = ").append(e.getSQL());
167 }
168 if (condition != null) {
169 buff.append("\nWHERE ").append(StringUtils.unEnclose(condition.getSQL()));
170 }
171 return buff.toString();
172 }
173
174 public void prepare() {
175 if (condition != null) {
176 condition.mapColumns(tableFilter, 0);
177 condition = condition.optimize(session);
178 condition.createIndexConditions(session, tableFilter);
179 }
180 for (int i = 0, size = columns.size(); i < size; i++) {
181 Column c = columns.get(i);
182 Expression e = expressionMap.get(c);
183 e.mapColumns(tableFilter, 0);
184 expressionMap.put(c, e.optimize(session));
185 }
186 PlanItem item = tableFilter.getBestPlanItem(session, 1);
187 tableFilter.setPlanItem(item);
188 tableFilter.prepare();
189 }
190
191 public boolean isTransactional() {
192 return true;
193 }
194
195 public ResultInterface queryMeta() {
196 return null;
197 }
198
199 public int getType() {
200 return CommandInterface.UPDATE;
201 }
202
203 public void setLimit(Expression limit) {
204 this.limitExpr = limit;
205 }
206
207 public boolean isCacheable() {
208 return true;
209 }
210
211 }
212