KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > sql > generator > UpdateQueryPlan


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * UpdateQueryPlan.java
26  *
27  * Created on October 3, 2001
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore.sql.generator;
32
33 import org.netbeans.modules.dbschema.ColumnElement;
34 import org.netbeans.modules.dbschema.TableElement;
35 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
36 import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
37 import com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager;
38 import com.sun.jdo.spi.persistence.support.sqlstore.Transaction;
39 import com.sun.jdo.spi.persistence.support.sqlstore.model.*;
40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateJoinTableDesc;
41 import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl;
42 import com.sun.jdo.spi.persistence.utility.I18NHelper;
43
44 import java.util.ArrayList JavaDoc;
45 import java.util.Collection JavaDoc;
46 import java.util.Iterator JavaDoc;
47 import java.util.List JavaDoc;
48
49
50 /**
51  * This class is used to generated update/insert/delete statements.
52  */

53 public class UpdateQueryPlan extends QueryPlan {
54
55     /** Flag indicating whether we use batch update. */
56     private boolean batch = false;
57
58     private UpdateObjectDescImpl updateDesc;
59
60     public UpdateQueryPlan(ActionDesc desc, SQLStoreManager store) {
61         super(desc, store);
62         this.updateDesc = (UpdateObjectDescImpl) desc;
63         this.action = getAction(updateDesc.getUpdateAction());
64     }
65
66     private static int getAction(int updateAction) {
67         if (updateAction == ActionDesc.LOG_CREATE) {
68             return ACT_INSERT;
69         } else if (updateAction == ActionDesc.LOG_DESTROY) {
70             return ACT_DELETE;
71         } else if (updateAction == ActionDesc.LOG_UPDATE) {
72             return ACT_UPDATE;
73         } else {
74             return ACT_NOOP;
75         }
76     }
77
78     /**
79      * Specifies an field the data for which needs to be updated,
80      * and the mapped columns for which therefor need to be updated.
81      * For update queries the column will be put in the set lists,
82      * and for insert queries the column will be put into the
83      * insert values lists.
84      *
85      * @param fieldDesc Updated field corresponding to a column in the database.
86      * @param value New value.
87      */

88     private void addColumn(LocalFieldDesc fieldDesc, Object JavaDoc value) {
89
90         // Ignore secondary tracked fields.
91
if ((fieldDesc.sqlProperties & FieldDesc.PROP_SECONDARY_TRACKED_FIELD) > 0) {
92             return;
93         }
94
95         for (Iterator JavaDoc iter = fieldDesc.getColumnElements(); iter.hasNext(); ) {
96             ColumnElement columnElement = (ColumnElement) iter.next();
97             TableElement tableElement = columnElement.getDeclaringTable();
98
99             if (tableElement == null) {
100                 throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
101                         "core.configuration.fieldnotable", // NOI18N
102
fieldDesc.getName()));
103             }
104
105             QueryTable t = findQueryTable(tableElement);
106             UpdateStatement s = null;
107
108             if (t == null) {
109                 t = addQueryTable(tableElement, null);
110                 s = (UpdateStatement) addStatement(t);
111             } else {
112                 s = (UpdateStatement) getStatement(t);
113             }
114
115             if (fieldDesc.isVersion() && action == ACT_UPDATE) {
116                 // For update, version columns will be flagged specially.
117
s.addVersionColumn(columnElement);
118             } else {
119                 s.addColumn(columnElement, value);
120             }
121
122         }
123     }
124
125     public void build() {
126         build(false);
127     }
128
129     /**
130      * Builds a UpdateQueryPlan for an object based update
131      * type (i.e. insert, update, delete) ActionDesc.
132      *
133      * @param batch Flag indicating whether we use batch update.
134      */

135     public void build(boolean batch) {
136
137         if ((status & ST_BUILT) > 0) return;
138
139         this.batch = batch;
140
141         generateStatements();
142
143         addColumns();
144
145         if (statements.size() > 0) {
146             processStatements();
147         }
148
149         processJoinTables();
150
151         status = status | ST_BUILT;
152     }
153
154     private void generateStatements() {
155         // For insert and delete we build a statement for each table
156
if ((action == ACT_DELETE) || (action == ACT_INSERT)) {
157             Iterator JavaDoc iter = config.getTables();
158             while (iter.hasNext()) {
159                 TableDesc t = (TableDesc) iter.next();
160
161                 // Skip join tables
162
if (!t.isJoinTable()) {
163                     if (findQueryTable(t.getTableElement()) == null)
164                         addStatement(addQueryTable(t));
165                 }
166             }
167
168             // For insert statements, we need to reverse the order.
169
if (action == ACT_INSERT) {
170                 int i = 0;
171                 int j = statements.size() - 1;
172
173                 while (i < j) {
174                     Statement s = (Statement) statements.get(i);
175                     statements.set(i, statements.get(j));
176                     statements.set(j, s);
177                     i++;
178                     j--;
179                 }
180             }
181         }
182     }
183
184     /**
185      * For inserts and updates we figure out values (they might be hidden)
186      * and add the columns necessary. <code>addColumn</code> will figure out
187      * which tables need to be included.
188      */

189     private void addColumns() {
190         if ((action == ACT_UPDATE) || (action == ACT_INSERT)) {
191             List JavaDoc updatedFields = updateDesc.getUpdatedFields();
192             int size = (updatedFields != null) ? updatedFields.size() : 0;
193             for (int i = 0; i < size; i++) {
194                 LocalFieldDesc f = (LocalFieldDesc) updatedFields.get(i);
195                 Object JavaDoc value = batch ? f : updateDesc.getAfterValue(f);
196                 addColumn(f, value);
197             }
198         }
199     }
200
201     private void addConstraints(UpdateStatement statement,
202                                 ArrayList JavaDoc localFields,
203                                 ArrayList JavaDoc foreignFields,
204                                 ArrayList JavaDoc columns) {
205
206         boolean isBeforeImageRequired = updateDesc.isBeforeImageRequired();
207         for (int i = 0; i < localFields.size(); i++) {
208             LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
209             LocalFieldDesc ff = (LocalFieldDesc) foreignFields.get(i);
210             ColumnElement ce = (ColumnElement) columns.get(i);
211
212             addConstraint(statement, lf, ff, ce, isBeforeImageRequired);
213         }
214
215         // Add the constraint on the version field if needed.
216
if (getConfig().hasVersionConsistency() && action != ACT_INSERT) {
217             QueryTable table = (QueryTable) statement.getQueryTables().get(0);
218             LocalFieldDesc versionField = table.getTableDesc().getVersionField();
219             ColumnElement ce = (ColumnElement) versionField.getColumnElements().next();
220
221             addConstraint(statement, versionField, versionField, ce, false);
222         }
223
224         statement.markConstraintAdded();
225     }
226
227     private void addConstraint(UpdateStatement statement,
228                                LocalFieldDesc lf,
229                                LocalFieldDesc ff,
230                                ColumnElement ce,
231                                boolean isBeforeImageRequired) {
232
233         if (action != ACT_INSERT) {
234             if (batch) {
235                 statement.addConstraint(ce, lf, ff);
236             }
237             else {
238                 Object JavaDoc value = isBeforeImageRequired ?
239                     updateDesc.getBeforeValue(ff) : updateDesc.getAfterValue(ff);
240                 statement.addConstraint(lf, value);
241             }
242         } else {
243             Object JavaDoc value = batch ? ff : updateDesc.getAfterValue(ff);
244             statement.addColumn(ce, value);
245         }
246     }
247
248     private void addSecondaryTableConstraint(UpdateStatement statement) {
249         QueryTable table = (QueryTable) statement.getQueryTables().get(0);
250         ReferenceKeyDesc key = table.getTableDesc().getPrimaryTableKey();
251
252         ArrayList JavaDoc localFields = key.getReferencingKey().getFields();
253         ArrayList JavaDoc foreignFields = key.getReferencedKey().getFields();
254         ArrayList JavaDoc columns = key.getReferencingKey().getColumns();
255
256         addConstraints(statement, localFields, foreignFields, columns);
257     }
258
259     private void addBasetableConstraint(UpdateStatement statement) {
260         QueryTable table = (QueryTable) statement.getQueryTables().get(0);
261         KeyDesc key = table.getTableDesc().getKey();
262
263         ArrayList JavaDoc localFields = key.getFields();
264         ArrayList JavaDoc columns = key.getColumns();
265
266         addConstraints(statement, localFields, localFields, columns);
267     }
268
269     private void processRelatedStatements(UpdateStatement statement) {
270         ArrayList JavaDoc secondaryTableStatements = statement.getSecondaryTableStatements();
271
272         if (secondaryTableStatements != null) {
273             for (int i = 0; i < secondaryTableStatements.size(); i++) {
274                 UpdateStatement secondaryTableStatement = (UpdateStatement) secondaryTableStatements.get(i);
275
276                 if (!secondaryTableStatement.isConstraintAdded()) {
277                     processRelatedStatements(secondaryTableStatement);
278
279                     addSecondaryTableConstraint(secondaryTableStatement);
280                 }
281             }
282         }
283     }
284
285     protected void processStatements() {
286         int size = statements.size();
287
288         if (size > 1) {
289             super.processStatements();
290
291             for (int i = 0; i < size; i++) {
292                 UpdateStatement statement = (UpdateStatement) statements.get(i);
293
294                 if (!statement.isConstraintAdded())
295                     processRelatedStatements(statement);
296             }
297         }
298
299         UpdateStatement masterStatement = null;
300
301         if (size == 1)
302             masterStatement = (UpdateStatement) statements.get(0);
303         else {
304             // Look for the master statement. It should be the one
305
// with no constraints added.
306
for (int i = 0; i < size; i++) {
307                 masterStatement = (UpdateStatement) statements.get(i);
308
309                 if (!masterStatement.isConstraintAdded()) break;
310             }
311         }
312
313         if (action != ACT_INSERT)
314             addBasetableConstraint(masterStatement);
315
316         if ((action != ACT_INSERT) && (updateDesc.getConcurrency() != null))
317             updateDesc.getConcurrency().update(this);
318     }
319
320     private void processJoinTables() {
321         Collection JavaDoc fields = updateDesc.getUpdatedJoinTableFields();
322
323         if (fields == null) return;
324
325         Iterator JavaDoc fieldIter = fields.iterator();
326
327         ArrayList JavaDoc deleteStatements = new ArrayList JavaDoc();
328         ArrayList JavaDoc insertStatements = new ArrayList JavaDoc();
329
330         while (fieldIter.hasNext()) {
331             ForeignFieldDesc f = (ForeignFieldDesc) fieldIter.next();
332             Collection JavaDoc descs = updateDesc.getUpdateJoinTableDescs(f);
333             Iterator JavaDoc descIter = descs.iterator();
334
335             ColumnElement c = (ColumnElement) f.assocLocalColumns.get(0);
336             QueryTable t = addQueryTable(config.findTableDesc(c.getDeclaringTable()));
337
338             while (descIter.hasNext()) {
339                 UpdateJoinTableDesc desc = (UpdateJoinTableDesc) descIter.next();
340                 int action = getAction(desc.getAction());
341
342                 UpdateStatement s = (UpdateStatement) createStatement(t);
343                 s.setAction(action);
344
345                 if (action == ACT_INSERT) {
346                     insertStatements.add(s);
347                 } else if (action == ACT_DELETE) {
348
349                     // RESOLVE: There are redundant deletes from join tables that causes
350
// update to fail with no rows affected. To work around this problem
351
// for now, we set the minAffectedRows to 0.
352
// We need to figure out why there are redundant deletes.
353

354                     s.minAffectedRows = 0;
355                     deleteStatements.add(s);
356                 }
357
358                 s.addLocalConstraints(action, f, desc.getParentStateManager());
359                 s.addForeignConstraints(action, f, desc.getForeignStateManager());
360             }
361         }
362
363         // All join table delete statements have to go first and all
364
// join table insert statements have to go last.
365

366         ArrayList JavaDoc oldStatements = statements;
367         statements = deleteStatements;
368         statements.addAll(oldStatements);
369         statements.addAll(insertStatements);
370     }
371
372     protected Statement newStatement() {
373         return new UpdateStatement(store.getVendorType(), this, batch);
374     }
375
376     /**
377      * Determines if the amount of batched operations exceeded a threshold.
378      * @param tran the transaction
379      * @return true if the amount of batched operations exceeded a threshold
380      */

381     public boolean checkBatchThreshold(Transaction tran)
382     {
383         for (int i = 0, size = statements.size(); i < size; i++) {
384             UpdateStatement updateStatement = (UpdateStatement) statements.get(i);
385             if (updateStatement.exceedsBatchThreshold(tran))
386                 return true;
387         }
388         return false;
389     }
390
391 }
392
Popular Tags