KickJava   Java API By Example, From Geeks To Geeks.

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


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  * UpdateStatement.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 com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager;
35 import com.sun.jdo.spi.persistence.support.sqlstore.Transaction;
36 import com.sun.jdo.spi.persistence.support.sqlstore.database.DBVendorType;
37 import com.sun.jdo.spi.persistence.support.sqlstore.model.ForeignFieldDesc;
38 import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
39 import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl;
40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.ConstraintValue;
41
42 import java.sql.Connection JavaDoc;
43 import java.sql.SQLException JavaDoc;
44 import java.util.*;
45
46 /**
47  * This class is used to generate update/insert/delete statements.
48  */

49 public class UpdateStatement extends Statement implements Cloneable JavaDoc {
50
51     public int minAffectedRows;
52
53     private Map dbStatementCache = new HashMap();
54
55     /** The UpdateQueryplan */
56     UpdateQueryPlan plan;
57
58     /** List of ColumnRef for the where clause used during batch. */
59     private List columnRefsForWhereClause;
60
61     /** List of version columns */
62     private List versionColumns;
63
64     /** Flag indicating whether we use batch. */
65     private boolean batch = false;
66
67     /** Insert values for INSERT statements. */
68     private StringBuffer JavaDoc values;
69
70     /** */
71     private boolean isConstraintAdded;
72
73     /** Name of the USE_BATCH property. */
74     public static final String JavaDoc UPDATE_VERSION_COL_PROPERTY =
75         "com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UPDATE_VERSION_COL"; // NOI18N
76

77     /**
78      * Property to swich on/off updating of version col.
79      * Note, the default is true, meaning we try to update version col if the
80      * property is not specified.
81      */

82     private static final boolean UPDATE_VERSION_COL = Boolean.valueOf(
83         System.getProperty(UPDATE_VERSION_COL_PROPERTY, "true")).booleanValue(); // NOI18N
84

85
86     public UpdateStatement(DBVendorType vendorType, UpdateQueryPlan plan, boolean batch) {
87         super(vendorType);
88         this.plan = plan;
89         columnRefsForWhereClause = new ArrayList();
90         this.batch = batch;
91         minAffectedRows = 1;
92     }
93
94     public void addColumn(ColumnElement columnElement, Object JavaDoc value) {
95         addColumnRef(new ColumnRef(columnElement, value));
96     }
97
98     /**
99      * Batch helper method. Adds the columnElement to the list of
100      * ColumnRefs for the where clause and then calls addConstraint.
101      */

102     protected void addConstraint(ColumnElement columnElement,
103                                  LocalFieldDesc lf, Object JavaDoc value) {
104         columnRefsForWhereClause.add(new ColumnRef(columnElement, value));
105         addConstraint(lf, value);
106     }
107
108     /** Calculates the index of the where clause ColumnRefs */
109     private void calculateWhereClauseColumnRefIndexes() {
110         // calculate where clause column ref indexes
111
// NOTE, the sqlstore processes the constraints in reverse order,
112
// so start with the last index and decrement
113
int nextIndex = columns.size() + columnRefsForWhereClause.size();
114         for (Iterator i = columnRefsForWhereClause.iterator(); i.hasNext(); ) {
115             ColumnRef columnRef = (ColumnRef)i.next();
116             columnRef.setIndex(nextIndex--);
117         }
118     }
119
120     public boolean isConstraintAdded() {
121         return isConstraintAdded;
122     }
123
124     public void markConstraintAdded() {
125         isConstraintAdded = true;
126     }
127
128     /** @inheritDoc */
129     public QueryPlan getQueryPlan() {
130          return plan;
131     }
132
133     /**
134      * @inheritDoc
135      */

136     protected void generateStatementText() {
137
138         statementText = new StringBuffer JavaDoc();
139
140         StringBuffer JavaDoc columnList = generateColumnText();
141         StringBuffer JavaDoc constraint = processConstraints();
142         String JavaDoc tableName = ((QueryTable) tableList.get(0)).getTableDesc().getName();
143
144         // Create the query filling in the column list, table name, etc.
145
switch (action) {
146             case QueryPlan.ACT_UPDATE:
147                 statementText.append("update ");// NOI18N
148
appendQuotedText(statementText, tableName);
149                 statementText.append(" set ").append(columnList).append(" where ").append(constraint); // NOI18N
150
break;
151
152             case QueryPlan.ACT_DELETE:
153                 statementText.append("delete from ");// NOI18N
154
appendQuotedText(statementText, tableName);
155                 statementText.append(" where ").append(constraint); // NOI18N
156
break;
157
158             case QueryPlan.ACT_INSERT:
159                 statementText.append("insert into ");// NOI18N
160
appendQuotedText(statementText, tableName);
161                 statementText.append("(").append(columnList).// NOI18N
162
append(") values ").append("(").append(values).append(")"); // NOI18N
163
break;
164         }
165
166         calculateWhereClauseColumnRefIndexes();
167     }
168
169     private StringBuffer JavaDoc generateColumnText() {
170         StringBuffer JavaDoc columnList = new StringBuffer JavaDoc();
171         int numValues = -1;
172
173         for (int i = 0; i < columns.size(); i++) {
174             ColumnRef c = (ColumnRef) columns.get(i);
175
176             if (columnList.length() > 0) {
177                 columnList.append(", "); // NOI18N
178
}
179             switch (action) {
180                 case QueryPlan.ACT_UPDATE:
181                     appendQuotedText(columnList, c.getName());
182                     columnList.append("= ?"); // NOI18N
183
break;
184
185                 case QueryPlan.ACT_INSERT:
186                     appendQuotedText(columnList, c.getName());
187                     if (i == 0) {
188                         values = new StringBuffer JavaDoc().append(" ?"); // NOI18N
189
} else {
190                         values.append(", ?"); // NOI18N
191
}
192                     break;
193             }
194
195             // Do not create an InputValue in the case of batch update.
196
// Method bindInputValues will get the value using the ColumnRef.
197
if (!batch &&
198                 ((action == QueryPlan.ACT_UPDATE) ||
199                     (action == QueryPlan.ACT_INSERT))) {
200                 numValues = numValues + 1;
201                 InputValue val = new InputValue(c.getValue(), c.getColumnElement());
202                 inputDesc.values.add(numValues, val);
203             }
204         }
205
206         appendVersionColumnUpdateClause(columnList);
207
208         return columnList;
209     }
210
211     /**
212      * Appends clause to update version column. The generated clause will be of
213      * the following form
214      * <code> versionColumnName = versionColumnNane + 1 </code>
215      * @param setClause Text for the set clause of update statement
216      */

217     private void appendVersionColumnUpdateClause(StringBuffer JavaDoc setClause) {
218         if(UPDATE_VERSION_COL) {
219             if (versionColumns != null)
220             {
221                 for (int i = 0; i < versionColumns.size(); i++) {
222                     ColumnElement columnElement = (ColumnElement) versionColumns.get(i);
223                     String JavaDoc columnName = columnElement.getName().getName();
224                     setClause.append(", ");
225                     appendQuotedText(setClause, columnName);
226                     setClause.append(" = ");
227                     appendQuotedText(setClause, columnName);
228                     setClause.append(" + ");
229                     setClause.append("1");
230                 }
231             }
232         }
233     }
234
235
236     public void addLocalConstraints(int action, ForeignFieldDesc f, SQLStateManager sm) {
237         for (int i = 0; i < f.localFields.size(); i++) {
238             LocalFieldDesc lf = (LocalFieldDesc) f.localFields.get(i);
239
240             if (action == QueryPlan.ACT_INSERT) {
241                 // For inserts into the join table, we get the values we are inserting
242
// for the parent object and the added object.
243
ColumnElement lc = (ColumnElement) f.assocLocalColumns.get(i);
244
245                 addColumn(lc, lf.getValue(sm));
246             } else if (action == QueryPlan.ACT_DELETE) {
247                 LocalFieldDesc alf = (LocalFieldDesc) f.assocLocalFields.get(i);
248
249                 // For deletes from the join table, we get the constraint values
250
// from the parent object and the remove object.
251
addConstraint(alf, lf.getValue(sm));
252             }
253         }
254     }
255
256     public void addForeignConstraints(int action, ForeignFieldDesc f, SQLStateManager sm) {
257         for (int i = 0; i < f.foreignFields.size(); i++) {
258             LocalFieldDesc ff = (LocalFieldDesc) f.foreignFields.get(i);
259
260             if (action == QueryPlan.ACT_INSERT) {
261                 // For inserts into the join table, we get the values we are inserting
262
// for the parent object and the added object.
263
ColumnElement fc = (ColumnElement) f.assocForeignColumns.get(i);
264
265                 addColumn(fc, ff.getValue(sm));
266             } else if (action == QueryPlan.ACT_DELETE) {
267                 LocalFieldDesc aff = (LocalFieldDesc) f.assocForeignFields.get(i);
268
269                 // For deletes from the join table, we get the constraint values
270
// from the parent object and the remove object.
271
addConstraint(aff, ff.getValue(sm));
272             }
273         }
274     }
275
276     /**
277      * Redefines processConstraintValue in order to skip the creation of
278      * an InputValue in the case of batch.
279      */

280     protected void processConstraintValue(ConstraintValue node, StringBuffer JavaDoc result) {
281         result.append("?"); // NOI18N
282
if (!batch)
283             generateInputValueForConstraintValueNode(node);
284     }
285
286     /**
287      * Returns the cached db statement for the specified connection.
288      * If there is not any statement for this connection in the cache,
289      * then a new statement is created.
290      * @param tran the transaction
291      * @param conn the connection
292      * @return the statement
293      */

294     public DBStatement getDBStatement(Transaction tran, Connection JavaDoc conn)
295         throws SQLException JavaDoc
296     {
297         DBStatement dbStatement = null;
298
299         synchronized (dbStatementCache)
300         {
301             // dbStatement cachelookup
302
dbStatement = (DBStatement)dbStatementCache.get(tran);
303
304             if (dbStatement == null) {
305                 dbStatement = new DBStatement(conn, getText(),
306                                               tran.getUpdateTimeout());
307                 // put dbStatement in cache
308
dbStatementCache.put(tran, dbStatement);
309             }
310         }
311
312         return dbStatement;
313     }
314
315     /** */
316     public boolean exceedsBatchThreshold(Transaction tran)
317     {
318         synchronized (dbStatementCache)
319         {
320             DBStatement dbStatement = (DBStatement)dbStatementCache.get(tran);
321             return (dbStatement != null) && dbStatement.exceedsBatchThreshold();
322         }
323     }
324
325     /**
326      * Removes the db statement for the specified connection from the cache
327      * and closes this statement.
328      * @param tran the transaction
329      */

330     public DBStatement removeDBStatement(Transaction tran)
331     {
332         synchronized (dbStatementCache)
333         {
334             DBStatement s = (DBStatement)dbStatementCache.remove(tran);
335             return s;
336         }
337     }
338
339     public void bindInputColumns(DBStatement s,
340                                  UpdateObjectDescImpl updateDesc)
341             throws SQLException JavaDoc {
342
343         // bind set clause (if necessary)
344
for (Iterator i = getColumnRefs().iterator(); i.hasNext(); ) {
345             bindInputColumn(s, (ColumnRef)i.next(), updateDesc, false );
346         }
347         // bind where clause (if necessary)
348
for (Iterator i = columnRefsForWhereClause.iterator(); i.hasNext(); ) {
349             bindInputColumn(s, (ColumnRef) i.next(), updateDesc,
350                     updateDesc.isBeforeImageRequired());
351         }
352
353     }
354
355     /**
356      * Binds the value in the specified update descriptor corresponding
357      * with the specified column reference to the specified statement.
358      * @param stmt the statement
359      * @param columnRef the column reference
360      * @param updateDesc the update descriptor
361      * @throws SQLException thrown by setter methods on java.sql.PreparedStatement
362      */

363     private void bindInputColumn(DBStatement stmt,
364                                  ColumnRef columnRef,
365                                  UpdateObjectDescImpl updateDesc,
366                                  boolean getBeforeValue) throws SQLException JavaDoc {
367
368         Object JavaDoc inputValue = getInputValue(updateDesc, columnRef, getBeforeValue);
369         stmt.bindInputColumn(columnRef.getIndex(), inputValue,
370                 columnRef.getColumnElement(), vendorType);
371     }
372
373     /**
374      * Get Input values to be bound to this statement.
375      * @param updateDesc The update descriptor.
376      * @return An Object array containing input values to be bound to this statement.
377      */

378     private Object JavaDoc[] getInputValues(UpdateObjectDescImpl updateDesc) {
379         Object JavaDoc[] inputValues =
380                 new Object JavaDoc[getColumnRefs().size() + columnRefsForWhereClause.size()];
381         for (Iterator i = getColumnRefs().iterator(); i.hasNext(); ) {
382             ColumnRef columnRef = (ColumnRef)i.next();
383             // columnRef's index are 1 based.
384
inputValues[columnRef.getIndex() - 1] = getInputValue(updateDesc, columnRef, false);
385         }
386         final boolean getBeforeValue = updateDesc.isBeforeImageRequired();
387         for (Iterator i = columnRefsForWhereClause.iterator(); i.hasNext(); ) {
388             ColumnRef columnRef = (ColumnRef)i.next();
389             inputValues[columnRef.getIndex() - 1] = getInputValue(updateDesc, columnRef, getBeforeValue);
390         }
391         return inputValues;
392     }
393
394     /**
395      * Gets formatted sql text corrsponding to this statement object. The text
396      * also contains values for input to the statement.
397      * @param updateDesc the updateDesc.
398      * @return formatted sql text corrsponding to this statement object.
399      */

400     public String JavaDoc getFormattedSQLText(UpdateObjectDescImpl updateDesc) {
401         return formatSqlText(getText(), getInputValues(updateDesc));
402     }
403
404     /**
405      * Gets input value corrsponding to given columnRef from given updateDesc
406      * @param updateDesc updateDesc pointing to the input values
407      * @param columnRef The columnRef. It always contains
408      * the <code>LocalFieldDesc</code> for the field.
409      * @param getBeforeValue If true, value returned is fetched from beforeImage
410      * if false, the value returned is fetched from afterImage.
411      * @return input value corrsponding to given columnRef from given updateDesc.
412      */

413     private static Object JavaDoc getInputValue(UpdateObjectDescImpl updateDesc,
414                                         ColumnRef columnRef,
415                                         boolean getBeforeValue) {
416         Object JavaDoc value;
417         LocalFieldDesc field = (LocalFieldDesc) columnRef.getValue();
418
419         if (field.isVersion()) {
420             // Bind the value from the after image for version fields,
421
// as they're incremented internally after each flush.
422
// Version fields must not be modified from "outside".
423
value = updateDesc.getAfterValue(field);
424         } else {
425             value = getBeforeValue ? updateDesc.getBeforeValue(field) :
426                     updateDesc.getAfterValue(field);
427         }
428
429         return value;
430     }
431
432     public void addVersionColumn(ColumnElement versionColumn) {
433         if (versionColumns == null) {
434             versionColumns = new ArrayList();
435         }
436         versionColumns.add(versionColumn);
437     }
438 }
439
Popular Tags