KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > queryframework > ExpressionQueryMechanism


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
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
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 in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.queryframework;
23
24 import java.util.*;
25
26 import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
27 import oracle.toplink.essentials.internal.helper.*;
28 import oracle.toplink.essentials.internal.expressions.*;
29 import oracle.toplink.essentials.expressions.*;
30 import oracle.toplink.essentials.logging.SessionLog;
31 import oracle.toplink.essentials.mappings.DatabaseMapping;
32 import oracle.toplink.essentials.mappings.DirectCollectionMapping;
33 import oracle.toplink.essentials.mappings.ManyToManyMapping;
34 import oracle.toplink.essentials.exceptions.*;
35 import oracle.toplink.essentials.mappings.OneToOneMapping;
36 import oracle.toplink.essentials.queryframework.*;
37 import oracle.toplink.essentials.descriptors.InheritancePolicy;
38 import oracle.toplink.essentials.descriptors.DescriptorQueryManager;
39 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
40 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
41 import oracle.toplink.essentials.internal.sessions.AbstractSession;
42 import oracle.toplink.essentials.descriptors.ClassDescriptor;
43
44 /**
45  * <p><b>Purpose</b>:
46  * Mechanism used for all expression read queries.
47  * ExpressionQueryInterface understands how to deal with expressions.
48  * <p>
49  * <p><b>Responsibilities</b>:
50  * Translates the expression and creates the appropriate SQL statements.
51  * Retrieves the data from the database and return the results to the query.
52  *
53  * @author Yvon Lavoie
54  * @since TOPLink/Java 1.0
55  */

56 public class ExpressionQueryMechanism extends StatementQueryMechanism {
57     protected Expression selectionCriteria;
58
59     /**
60      * Initialize the state of the query
61      * @param query - owner of mechanism
62      */

63     public ExpressionQueryMechanism(DatabaseQuery query) {
64         super(query);
65     }
66
67     /**
68      * Initialize the state of the query
69      * @param query - owner of mechanism
70      * @param expression - selection criteria
71      */

72     public ExpressionQueryMechanism(DatabaseQuery query, Expression expression) {
73         super(query);
74         this.selectionCriteria = expression;
75     }
76
77     /**
78      * Alias the supplied fields with respect to the expression node. Return copies of the fields
79      */

80     protected Vector aliasFields(ObjectExpression node, Vector fields) {
81         Vector result = new Vector(fields.size());
82
83         for (Enumeration e = fields.elements(); e.hasMoreElements();) {
84             DatabaseField eachField = (DatabaseField)((DatabaseField)e.nextElement()).clone();
85             eachField.setTable(node.aliasForTable(eachField.getTable()));
86             result.addElement(eachField);
87         }
88
89         return result;
90     }
91
92     /**
93      * If the fields in the statement have breen pre-set, e.g. for a subset of the fields
94      * in a partial attribute read, report query, or just a query for the class indicator,
95      * then try to alias those. Right now this just guesses that they're all from the base.
96      */

97     public Vector aliasPresetFields(SQLSelectStatement statement) {
98         Vector fields = statement.getFields();
99         Expression exp = statement.getWhereClause();
100
101         if (exp == null) {
102             return fields;
103         } else {
104             ExpressionBuilder base = exp.getBuilder();
105             return aliasFields(base, fields);
106         }
107     }
108
109     /**
110      * Create the appropriate where clause.
111      * Since this is where the selection criteria gets cloned for the first time
112      * (long after the owning query has been) many interesting things happen here.
113      */

114     public Expression buildBaseSelectionCriteria(boolean isSubSelect, Dictionary clonedExpressions) {
115         Expression expression = getSelectionCriteria();
116
117         // For Flashback: builder.asOf(value) counts as a non-trivial selection criteria.
118
// Also for bug 2612185 try to preserve the original builder as far as possible.
119
if ((expression == null) && getQuery().isObjectLevelReadQuery()) {
120             expression = ((ObjectLevelReadQuery)getQuery()).getExpressionBuilder();
121         }
122
123         // Subselects are not cloned, as they are cloned in the context of the parent expression.
124
if ((!isSubSelect) && (expression != null)) {
125             // For bug 2612185 specify the identity hashtable to be used in cloning so
126
// it is not thrown away at the end of cloning.
127
expression = expression.copiedVersionFrom(clonedExpressions);
128         }
129
130         DescriptorQueryManager queryManager = getDescriptor().getQueryManager();
131
132         
133         // Leaf inheritence and multiple table join.
134
if (queryManager.getAdditionalJoinExpression() != null) {
135             // CR#3701077, additional join not required for view, view does join.
136
if (! (getDescriptor().hasInheritance() && (getDescriptor().getInheritancePolicy().hasView()))) {
137                 Expression additionalJoin = (Expression)queryManager.getAdditionalJoinExpression();
138     
139                 // If there's an expression, then we know we'll have to rebuild anyway, so don't clone.
140
if (expression == null) {
141                     // Should never happen...
142
expression = (Expression)additionalJoin.clone();
143                 } else {
144                     expression = expression.and(additionalJoin);
145                 }
146                 expression.getBuilder().setWasAdditionJoinCriteriaUsed(true);
147             }
148         }
149
150         return expression;
151     }
152
153     /**
154      * Return the appropriate select statement containing the fields in the table.
155      */

156     public SQLSelectStatement buildBaseSelectStatement(boolean isSubSelect, Dictionary clonedExpressions) {
157         SQLSelectStatement selectStatement = new SQLSelectStatement();
158         selectStatement.setLockingClause(((ObjectLevelReadQuery)getQuery()).getLockingClause());
159         selectStatement.setDistinctState(((ObjectLevelReadQuery)getQuery()).getDistinctState());
160         selectStatement.setTables((Vector)getDescriptor().getTables().clone());
161         selectStatement.setWhereClause(buildBaseSelectionCriteria(isSubSelect, clonedExpressions));
162         if (getQuery().isReadAllQuery() && ((ReadAllQuery)getQuery()).hasOrderByExpressions()) {
163             selectStatement.setOrderByExpressions(((ReadAllQuery)getQuery()).getOrderByExpressions());
164         }
165         selectStatement.setTranslationRow(getTranslationRow());
166         return selectStatement;
167     }
168
169     /**
170      * Return the appropriate select statement containing the fields in the table.
171      * This is used as a second read to a concrete class with subclasses in an abstract-multiple table read.
172      */

173     protected SQLSelectStatement buildConcreteSelectStatement() {
174         // 2612538 - the default size of IdentityHashtable (32) is appropriate
175
IdentityHashtable clonedExpressions = new IdentityHashtable();
176         SQLSelectStatement selectStatement = buildBaseSelectStatement(false, clonedExpressions);
177
178         // Case of class with subclasses that also has instances on abstract-multiple table read.
179
if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().shouldReadSubclasses()) {
180             Expression concrete = (Expression)getDescriptor().getInheritancePolicy().getOnlyInstancesExpression();
181             if ((concrete != null) && (selectStatement.getWhereClause() != null)) {
182                 selectStatement.setWhereClause(selectStatement.getWhereClause().and(concrete));
183             } else if (concrete != null) {
184                 selectStatement.setWhereClause((Expression)concrete.clone());
185             }
186         }
187
188         selectStatement.setFields(getSelectionFields(selectStatement, false));
189         selectStatement.normalize(getSession(), getDescriptor(), clonedExpressions);
190         // Allow for joining indexes to be computed to ensure distinct rows
191
((ObjectLevelReadQuery)getQuery()).getJoinedAttributeManager().computeJoiningMappingIndexes(false, getSession(), 0);
192
193         return selectStatement;
194     }
195
196     /**
197      * Return the appropriate delete statement
198      * Passing of a call/ statement pair is used because the same pair
199      * may be used several times.
200      * More elegant orangement of passing just a statement and creating the call
201      * in the method was rejected because the same call would've been potentially
202      * re-created several times.
203      * Preconditions:
204      * if selectCallForExist != null then selectStatementForExist != null;
205      * if selectCallForNotExist != null then selectStatementForNotExist != null.
206      * @return SQLDeleteStatement
207      */

208     protected SQLDeleteStatement buildDeleteAllStatement(DatabaseTable table, Expression inheritanceExpression,
209                 SQLCall selectCallForExist, SQLSelectStatement selectStatementForExist,
210                 SQLCall selectCallForNotExist, SQLSelectStatement selectStatementForNotExist,
211                 Collection primaryKeyFields) {
212         if(selectCallForExist == null && selectCallForNotExist == null) {
213             return buildDeleteAllStatement(table, inheritanceExpression);
214         }
215         
216         SQLDeleteAllStatement deleteAllStatement = new SQLDeleteAllStatement();
217         deleteAllStatement.setTable(table);
218         deleteAllStatement.setTranslationRow(getTranslationRow());
219
220         if(inheritanceExpression != null) {
221             deleteAllStatement.setInheritanceExpression((Expression)inheritanceExpression.clone());
222         }
223
224         if(selectCallForExist != null) {
225             deleteAllStatement.setSelectCallForExist(selectCallForExist);
226             deleteAllStatement.setTableAliasInSelectCallForExist(getAliasTableName(selectStatementForExist, table));
227         }
228
229         if(selectCallForNotExist != null) {
230             deleteAllStatement.setSelectCallForNotExist(selectCallForNotExist);
231             deleteAllStatement.setTableAliasInSelectCallForNotExist(getAliasTableName(selectStatementForNotExist, table));
232         }
233
234         deleteAllStatement.setPrimaryKeyFieldsForAutoJoin(primaryKeyFields);
235
236         return deleteAllStatement;
237     }
238     
239     protected SQLDeleteStatement buildSQLDeleteAllStatementForMapping(SQLCall selectCallForExist, SQLSelectStatement selectStatementForExist, Vector sourceFields, Vector targetFields) {
240         DatabaseTable targetTable = ((DatabaseField)targetFields.firstElement()).getTable();
241         if(selectCallForExist == null) {
242             return buildDeleteAllStatement(targetTable);
243         }
244
245         SQLDeleteAllStatement deleteAllStatement = new SQLDeleteAllStatement();
246         
247         deleteAllStatement.setTable(targetTable);
248         deleteAllStatement.setTranslationRow(getTranslationRow());
249
250         deleteAllStatement.setSelectCallForExist(selectCallForExist);
251         DatabaseTable sourceTable = ((DatabaseField)sourceFields.firstElement()).getTable();
252         if(selectStatementForExist != null) {
253             deleteAllStatement.setTableAliasInSelectCallForExist(getAliasTableName(selectStatementForExist, sourceTable));
254         }
255
256         deleteAllStatement.setAliasedFieldsForJoin(sourceFields);
257         deleteAllStatement.setOriginalFieldsForJoin(targetFields);
258
259         return deleteAllStatement;
260     }
261     
262     protected static String JavaDoc getAliasTableName(SQLSelectStatement selectStatement, DatabaseTable table) {
263         if(!selectStatement.requiresAliases()) {
264             return null;
265         }
266         HashSet aliasTables = new HashSet();
267         Iterator itEntries = selectStatement.getTableAliases().entrySet().iterator();
268         DatabaseTable aliasTable = null;
269         while(itEntries.hasNext()) {
270             Map.Entry entry = (Map.Entry)itEntries.next();
271             if(table.equals(entry.getValue())) {
272                 aliasTable = (DatabaseTable)entry.getKey();
273                 aliasTables.add(aliasTable);
274             }
275         }
276         if(aliasTables.isEmpty()) {
277             return null;
278         } else if(aliasTables.size() == 1) {
279             return aliasTable.getQualifiedName();
280         }
281         // The table has several aliases,
282
// remove the aliases that used by DataExpressions
283
// with baseExpression NOT the expressionBuilder used by the statement
284
ExpressionIterator expIterator = new ExpressionIterator() {
285             public void iterate(Expression each) {
286                 if(each instanceof DataExpression) {
287                     DataExpression dataExpression = (DataExpression)each;
288                     DatabaseField field = dataExpression.getField();
289                     if(field != null) {
290                         if(dataExpression.getBaseExpression() != getStatement().getBuilder()) {
291                             ((Collection)getResult()).remove(dataExpression.getAliasedField().getTable());
292                         }
293                     }
294                 }
295             }
296             public boolean shouldIterateOverSubSelects() {
297                 return true;
298             }
299         };
300
301         expIterator.setStatement(selectStatement);
302         expIterator.setResult(aliasTables);
303         expIterator.iterateOn(selectStatement.getWhereClause());
304         
305         if(aliasTables.size() == 1) {
306             aliasTable = (DatabaseTable)aliasTables.iterator().next();
307             return aliasTable.getQualifiedName();
308         } else if(aliasTables.isEmpty()) {
309             // should never happen
310
return aliasTable.getQualifiedName();
311         } else {
312             // should never happen
313
aliasTable = (DatabaseTable)aliasTables.iterator().next();
314             return aliasTable.getQualifiedName();
315         }
316     }
317     
318     protected SQLDeleteStatement buildDeleteAllStatement() {
319         return buildDeleteAllStatement(getDescriptor().getDefaultTable());
320     }
321
322     protected SQLDeleteStatement buildDeleteAllStatement(Expression inheritanceExpression) {
323         return buildDeleteAllStatement(getDescriptor().getDefaultTable(), inheritanceExpression);
324     }
325
326     protected SQLDeleteStatement buildDeleteAllStatement(DatabaseTable table) {
327         return buildDeleteAllStatement(table, null);
328     }
329
330     protected SQLDeleteStatement buildDeleteAllStatement(DatabaseTable table, Expression inheritanceExpression) {
331         SQLDeleteStatement deleteStatement = new SQLDeleteStatement();
332
333         deleteStatement.setWhereClause(getSelectionCriteria());
334         if(deleteStatement.getWhereClause() != null) {
335             deleteStatement.setWhereClause((Expression)deleteStatement.getWhereClause().clone());
336             deleteStatement.getWhereClause().getBuilder().setSession(getSession());
337             deleteStatement.getWhereClause().getBuilder().setQueryClass(getQuery().getReferenceClass());
338         }
339         if(inheritanceExpression != null) {
340             if(deleteStatement.getWhereClause() != null) {
341                 deleteStatement.setWhereClause(deleteStatement.getWhereClause().and(inheritanceExpression));
342             } else {
343                 deleteStatement.setWhereClause((Expression)inheritanceExpression.clone());
344             }
345         }
346         deleteStatement.setTable(table);
347         deleteStatement.setTranslationRow(getTranslationRow());
348         return deleteStatement;
349     }
350
351     /**
352      * Return the appropriate delete statement
353      */

354     protected SQLDeleteStatement buildDeleteStatement(DatabaseTable table) {
355         SQLDeleteStatement deleteStatement = new SQLDeleteStatement();
356         Expression whereClause;
357         whereClause = getDescriptor().getObjectBuilder().buildDeleteExpression(table, getTranslationRow());
358
359         deleteStatement.setWhereClause(whereClause);
360         deleteStatement.setTable(table);
361         deleteStatement.setTranslationRow(getTranslationRow());
362         return deleteStatement;
363     }
364
365     /**
366      * Return the appropriate insert statement
367      */

368     protected SQLInsertStatement buildInsertStatement(DatabaseTable table) {
369         SQLInsertStatement insertStatement = new SQLInsertStatement();
370         insertStatement.setTable(table);
371         insertStatement.setModifyRow(getModifyRow());
372         return insertStatement;
373     }
374
375     /**
376      * Return the appropriate select statement containing the fields in the table.
377      */

378     protected SQLSelectStatement buildNormalSelectStatement() {
379         // From bug 2612185 Remember the identity hashtable used in cloning the selection criteria even in the normal case
380
// for performance, in case subqueries need it, or for order by expressions.
381
// 2612538 - the default size of IdentityHashtable (32) is appropriate
382
IdentityHashtable clonedExpressions = new IdentityHashtable();
383         SQLSelectStatement selectStatement = buildBaseSelectStatement(false, clonedExpressions);
384
385         // Case, normal read for branch inheritence class that reads subclasses all in its own table(s).
386
if (getDescriptor().hasInheritance()) {
387             getDescriptor().getInheritancePolicy().appendWithAllSubclassesExpression(selectStatement);
388         }
389
390         selectStatement.setFields(getSelectionFields(selectStatement, true));
391         selectStatement.setNonSelectFields(getNonSelectionFields());
392         selectStatement.normalize(getSession(), getDescriptor(), clonedExpressions);
393         // Allow for joining indexes to be computed to ensure distinct rows
394
((ObjectLevelReadQuery)getQuery()).getJoinedAttributeManager().computeJoiningMappingIndexes(true, getSession(),0);
395
396         return selectStatement;
397     }
398
399     /**
400      * Return the appropriate select statement containing the fields in the table.
401      * Similar to super except the buildBaseSelectStatement will look after setting
402      * the fields to select.
403      */

404     protected SQLSelectStatement buildReportQuerySelectStatement(boolean isSubSelect) {
405         return buildReportQuerySelectStatement(isSubSelect, false, null);
406     }
407     /**
408      * Customary inheritance expression is required for DeleteAllQuery and UpdateAllQuery preparation.
409      */

410     protected SQLSelectStatement buildReportQuerySelectStatement(boolean isSubSelect, boolean useCustomaryInheritanceExpression, Expression inheritanceExpression) {
411         // For bug 2612185: Need to know which original bases were mapped to which cloned bases.
412
// Note: subSelects are already cloned so this table is not needed.
413
// 2612538 - the default size of IdentityHashtable (32) is appropriate
414
IdentityHashtable clonedExpressions = isSubSelect ? null : new IdentityHashtable();
415         SQLSelectStatement selectStatement = buildBaseSelectStatement(isSubSelect, clonedExpressions);
416         selectStatement.setGroupByExpressions(((ReportQuery)getQuery()).getGroupByExpressions());
417         selectStatement.setHavingExpression(((ReportQuery)getQuery()).getHavingExpression());
418         if (getDescriptor().hasInheritance()) {
419             if(useCustomaryInheritanceExpression) {
420                 if(inheritanceExpression != null) {
421                     if (selectStatement.getWhereClause() == null) {
422                         selectStatement.setWhereClause((Expression)inheritanceExpression.clone());
423                     } else {
424                         selectStatement.setWhereClause(selectStatement.getWhereClause().and(inheritanceExpression));
425                     }
426                 }
427             } else {
428                 getDescriptor().getInheritancePolicy().appendWithAllSubclassesExpression(selectStatement);
429             }
430         }
431         Vector fieldExpressions = ((ReportQuery)getQuery()).getQueryExpressions();
432         int itemOffset = fieldExpressions.size();
433         for (Iterator items = ((ReportQuery)getQuery()).getItems().iterator(); items.hasNext();){
434             ReportItem item = (ReportItem) items.next();
435             if(item.isContructorItem()){
436                 ConstructorReportItem citem= (ConstructorReportItem)item;
437                 List reportItems = citem.getReportItems();
438                 int size = reportItems.size();
439                 for(int i=0;i<size;i++){
440                     item = (ReportItem)reportItems.get(i);
441                     extractStatementFromItem( item, clonedExpressions, selectStatement, fieldExpressions );
442                 }
443             }
444             else{
445                 extractStatementFromItem( item, clonedExpressions, selectStatement, fieldExpressions );
446             }
447         }
448             
449         selectStatement.setFields(fieldExpressions);
450         selectStatement.setNonSelectFields(((ReportQuery)getQuery()).getNonFetchJoinAttributeExpressions());
451         
452         // Subselects must be normalized in the context of the parent statement.
453
if (!isSubSelect) {
454             selectStatement.normalize(getSession(), getDescriptor(), clonedExpressions);
455         }
456
457         //calculate indexes after normalize to insure expressions are set up correctly
458
for (Iterator items = ((ReportQuery)getQuery()).getItems().iterator(); items.hasNext();){
459             ReportItem item = (ReportItem) items.next();
460             
461             if(item.isContructorItem()){
462                 ConstructorReportItem citem= (ConstructorReportItem)item;
463                 List reportItems = citem.getReportItems();
464                 int size = reportItems.size();
465                 for(int i=0;i<size;i++){
466                     item = (ReportItem)reportItems.get(i);
467                     itemOffset = computeAndSetItemOffset(item, itemOffset);
468                 }
469             }
470             else{
471                 itemOffset = computeAndSetItemOffset(item, itemOffset);
472             }
473         }
474
475         return selectStatement;
476     }
477     
478     
479     /**
480      * calculate indexes for an item, given the current Offset
481      */

482     protected int computeAndSetItemOffset(ReportItem item, int itemOffset){
483         item.setResultIndex(itemOffset);
484         if (item.getAttributeExpression() != null){
485             JoinedAttributeManager joinManager = item.getJoinedAttributeManager();
486             if (joinManager.hasJoinedExpressions()){
487                 itemOffset = joinManager.computeJoiningMappingIndexes(true, getSession(),itemOffset);
488             }else{
489                 if (item.getDescriptor() != null){
490                     itemOffset += item.getDescriptor().getAllFields().size();
491                 }else {
492                     ++itemOffset; //only a single attribute can be selected
493
}
494             }
495         }
496         return itemOffset;
497     }
498     
499     public void extractStatementFromItem(ReportItem item,IdentityHashtable clonedExpressions,SQLSelectStatement selectStatement,Vector fieldExpressions ){
500         if (item.getAttributeExpression() != null){
501                 // this allows us to modify the item expression without modifying the original in case of re-prepare
502
Expression attributeExpression = item.getAttributeExpression();
503                 ExpressionBuilder clonedBuilder = attributeExpression.getBuilder();
504                 if (clonedBuilder.wasQueryClassSetInternally() && ((ReportQuery)getQuery()).getExpressionBuilder() != clonedBuilder){
505                     // no class specified so use statement builder as it is non-parallel
506
// must have same builder as it will be initialized
507
clonedBuilder = selectStatement.getBuilder();
508                     attributeExpression = attributeExpression.rebuildOn(clonedBuilder);
509                 }else if (clonedExpressions != null && clonedExpressions.get(clonedBuilder) != null) {
510                     //The builder has been cloned ensure that the cloned builder is used
511
//in the items.
512
clonedBuilder = (ExpressionBuilder)clonedBuilder.copiedVersionFrom(clonedExpressions);
513                     attributeExpression = attributeExpression.rebuildOn(clonedBuilder);
514                 }
515                 if (attributeExpression.isExpressionBuilder()
516                     && item.getDescriptor().getQueryManager().getAdditionalJoinExpression() != null
517                     && !(((ExpressionBuilder)clonedBuilder).wasAdditionJoinCriteriaUsed()) ){
518                     if (selectStatement.getWhereClause() == null ) {
519                         selectStatement.setWhereClause(item.getDescriptor().getQueryManager().getAdditionalJoinExpression().rebuildOn(clonedBuilder));
520                     } else {
521                         selectStatement.setWhereClause(selectStatement.getWhereClause().and(item.getDescriptor().getQueryManager().getAdditionalJoinExpression().rebuildOn(clonedBuilder)));
522                     }
523                 }
524                 fieldExpressions.add(attributeExpression);
525                 JoinedAttributeManager joinManager = item.getJoinedAttributeManager();
526                 if (joinManager.hasJoinedExpressions()){
527                     fieldExpressions.addAll(joinManager.getJoinedAttributeExpressions());
528                     fieldExpressions.addAll(joinManager.getJoinedMappingExpressions());
529                 }
530         }
531     }
532
533     /**
534      * Return the appropriate select statement to perform a does exist check
535      * @param fields - fields for does exist check.
536      */

537     protected SQLSelectStatement buildSelectStatementForDoesExist(DatabaseField field) {
538         // Build appropriate select statement
539
SQLSelectStatement selectStatement;
540         selectStatement = new SQLSelectStatement();
541         selectStatement.addField(field);
542         selectStatement.setWhereClause(((Expression)getDescriptor().getObjectBuilder().getPrimaryKeyExpression().clone()).and(getDescriptor().getQueryManager().getAdditionalJoinExpression()));
543         selectStatement.setTranslationRow(getTranslationRow());
544
545         selectStatement.normalize(getSession(), getQuery().getDescriptor());
546         return selectStatement;
547     }
548
549     protected SQLUpdateAllStatement buildUpdateAllStatement(DatabaseTable table,
550                 HashMap databaseFieldsToValues,
551                 SQLCall selectCallForExist, SQLSelectStatement selectStatementForExist,
552                 Collection primaryKeyFields)
553     {
554         SQLUpdateAllStatement updateAllStatement = new SQLUpdateAllStatement();
555         updateAllStatement.setTable(table);
556         updateAllStatement.setTranslationRow(getTranslationRow());
557
558         HashMap databaseFieldsToValuesCopy = new HashMap(databaseFieldsToValues.size());
559         HashMap databaseFieldsToTableAliases = null;
560         Iterator it = databaseFieldsToValues.entrySet().iterator();
561         while(it.hasNext()) {
562             Map.Entry entry = (Map.Entry)it.next();
563             // for each table to be updated
564
DatabaseField field = (DatabaseField)entry.getKey();
565             // here's a Map of left hand fields to right hand expressions
566
Object JavaDoc value = entry.getValue();
567             if(value instanceof SQLSelectStatement) {
568                 SQLSelectStatement selStatement = (SQLSelectStatement)value;
569                 SQLCall selCall = (SQLCall)selStatement.buildCall(getSession());
570                 databaseFieldsToValuesCopy.put(field, selCall);
571                 if(databaseFieldsToTableAliases == null) {
572                     databaseFieldsToTableAliases = new HashMap();
573                     updateAllStatement.setPrimaryKeyFieldsForAutoJoin(primaryKeyFields);
574                 }
575                 databaseFieldsToTableAliases.put(field, getAliasTableName(selStatement, table));
576             } else {
577                 // should be Expression
578
databaseFieldsToValuesCopy.put(field, value);
579             }
580         }
581         updateAllStatement.setUpdateClauses(databaseFieldsToValuesCopy);
582         updateAllStatement.setDatabaseFieldsToTableAliases(databaseFieldsToTableAliases);
583         
584         if(selectCallForExist != null) {
585             updateAllStatement.setSelectCallForExist(selectCallForExist);
586             updateAllStatement.setTableAliasInSelectCallForExist(getAliasTableName(selectStatementForExist, table));
587             updateAllStatement.setPrimaryKeyFieldsForAutoJoin(primaryKeyFields);
588         } else {
589             updateAllStatement.setWhereClause(getSelectionCriteria());
590             if(updateAllStatement.getWhereClause() != null) {
591                 updateAllStatement.setWhereClause((Expression)updateAllStatement.getWhereClause().clone());
592                 updateAllStatement.getWhereClause().getBuilder().setSession(getSession());
593                 updateAllStatement.getWhereClause().getBuilder().setQueryClass(getQuery().getReferenceClass());
594             }
595         }
596
597         return updateAllStatement;
598     }
599     
600     /**
601      * Return the appropriate update statement
602      * @return SQLInsertStatement
603      */

604     protected SQLUpdateStatement buildUpdateStatement(DatabaseTable table) {
605         SQLUpdateStatement updateStatement = new SQLUpdateStatement();
606
607         updateStatement.setModifyRow(getModifyRow());
608         updateStatement.setTranslationRow(getTranslationRow());
609         updateStatement.setTable(table);
610         updateStatement.setWhereClause(getDescriptor().getObjectBuilder().buildUpdateExpression(table, getTranslationRow(), getModifyRow()));
611         return updateStatement;
612     }
613
614     /**
615      * Perform a cache lookup for the query
616      * This is only called from read object query.
617      * The query has already checked that the cache should be checked.
618      */

619     public Object JavaDoc checkCacheForObject(AbstractRecord translationRow, AbstractSession session) {
620         // For bug 2782991 a list of nearly 20 problems with this method have
621
// been fixed.
622
ReadObjectQuery query = getReadObjectQuery();
623         boolean conforming = ((query.shouldConformResultsInUnitOfWork() || getDescriptor().shouldAlwaysConformResultsInUnitOfWork()) && session.isUnitOfWork());
624
625         // Set the in memory query policy automatically for conforming queries, unless the
626
// user specifies the most cautious one.
627
InMemoryQueryIndirectionPolicy policyToUse = query.getInMemoryQueryIndirectionPolicy();
628         if (conforming && !policyToUse.shouldTriggerIndirection()) {
629             policyToUse = new InMemoryQueryIndirectionPolicy();
630             policyToUse.ignoreIndirectionExceptionReturnNotConformed();
631         }
632         Object JavaDoc cachedObject = null;
633         Vector selectionKey = null;
634         Expression selectionCriteria = getSelectionCriteria();
635
636         // Perform a series of cache checks, in the following order...
637
// 1: If selection key or selection object, lookup by primary key.
638
// 2: If selection criteria null, take the first instance in cache.
639
// 3: If exact primary key expression, lookup by primary key.
640
// 4: If inexact primary key expression, lookup by primary key and see if it conforms.
641
// 5: Perform a linear search on the cache, calling doesConform on each object.
642
// 6: (Conforming) Search through new objects.
643
// Each check is more optimal than the next.
644
// Finally: (Conforming) check that any positive result was not deleted in the UnitOfWork.
645
// 1: If selection key or selection object, do lookup by primary key.
646
//
647
if ((query.getSelectionKey() != null) || (query.getSelectionObject() != null)) {
648             if ((query.getSelectionKey() == null) && (query.getSelectionObject() != null)) {
649                 // Must be checked seperately as the expression and row is not yet set.
650
query.setSelectionKey(getDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(query.getSelectionObject(), session));
651             }
652             if (query.getSelectionKey() != null) {
653                 selectionKey = query.getSelectionKey();
654                 if (getDescriptor().shouldAcquireCascadedLocks()) {
655                     cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(selectionKey, query.getReferenceClass(), false, getDescriptor());
656                 } else {
657                     cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(selectionKey, query.getReferenceClass(), false, getDescriptor(), null);
658                 }
659             }
660         } else {
661             // 2: If selection criteria null, take any instance in cache.
662
//
663
if (selectionCriteria == null) {
664                 // In future would like to always return something from cache.
665
if (query.shouldConformResultsInUnitOfWork() || getDescriptor().shouldAlwaysConformResultsInUnitOfWork() || query.shouldCheckCacheOnly() || query.shouldCheckCacheThenDatabase()) {
666                     cachedObject = session.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(null, query.getReferenceClass(), translationRow, policyToUse, conforming, false, getDescriptor());
667                 }
668             } else {
669                 // 3: If can extract exact primary key expression, do lookup by primary key.
670
//
671
selectionKey = getDescriptor().getObjectBuilder().extractPrimaryKeyFromExpression(true, selectionCriteria, translationRow, session);
672
673                 // If an exact primary key was extracted or should check cache by exact
674
// primary key only this will become the final check.
675
if ((selectionKey != null) || query.shouldCheckCacheByExactPrimaryKey()) {
676                     if (selectionKey != null) {
677                         if (getDescriptor().shouldAcquireCascadedLocks()) {
678                             cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(selectionKey, query.getReferenceClass(), false, getDescriptor());
679                         } else {
680                             cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(selectionKey, query.getReferenceClass(), false, getDescriptor(), null);
681                         }
682                     }
683                     // Because it was exact primary key if the lookup failed then it is not there.
684
} else {
685                     // 4: If can extract inexact primary key, find one object by primary key and
686
// check if it conforms. Failure of this object to conform however does not
687
// rule out a cache hit.
688
//
689
Vector inexactSelectionKey = getDescriptor().getObjectBuilder().extractPrimaryKeyFromExpression(false, selectionCriteria, translationRow, session);// Check for any primary key in expression, may have other stuff.
690
if (inexactSelectionKey != null) {
691                         // PERF: Only use deferred lock when required.
692
if (getDescriptor().shouldAcquireCascadedLocks()) {
693                             cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(inexactSelectionKey, query.getReferenceClass(), false, getDescriptor());
694                         } else {
695                             cachedObject = session.getIdentityMapAccessorInstance().getFromIdentityMap(inexactSelectionKey, query.getReferenceClass(), false, getDescriptor(), null);
696                         }
697                         if (cachedObject != null) {
698                             // Must ensure that it matches the expression.
699
try {
700                                 // PERF: 3639015 - cloning the expression no longer required
701
// when using the root session
702
selectionCriteria.getBuilder().setSession(session.getRootSession(query));
703                                 selectionCriteria.getBuilder().setQueryClass(getDescriptor().getJavaClass());
704                                 if (!selectionCriteria.doesConform(cachedObject, session, translationRow, policyToUse)) {
705                                     cachedObject = null;
706                                 }
707                             } catch (QueryException exception) {// Ignore if expression too complex.
708
if (query.shouldCheckCacheOnly()) {// Throw on only cache.
709
throw exception;
710                                 }
711                                 cachedObject = null;
712                             }
713                         }
714                     }
715
716                     // 5: Perform a linear search of the cache, calling expression.doesConform on each element.
717
// This is a last resort linear time search of the identity map.
718
// This can be avoided by setting check cache by (inexact/exact) primary key on the query.
719
// That flag becomes invalid in the conforming case (bug 2609611: SUPPORT CONFORM RESULT IN UOW IN CONJUNCTION WITH OTHER IN-MEMORY FEATURES)
720
// so if conforming must always do this linear search, but at least only on
721
// objects registered in the UnitOfWork.
722
//
723
boolean conformingButOutsideUnitOfWork = ((query.shouldConformResultsInUnitOfWork() || getDescriptor().shouldAlwaysConformResultsInUnitOfWork()) && !session.isUnitOfWork());
724                     if ((cachedObject == null) && (conforming || (!query.shouldCheckCacheByPrimaryKey() && !conformingButOutsideUnitOfWork))) {
725                         // PERF: 3639015 - cloning the expression no longer required
726
// when using the root session
727
if (selectionCriteria != null) {
728                             selectionCriteria.getBuilder().setSession(session.getRootSession(query));
729                             selectionCriteria.getBuilder().setQueryClass(getDescriptor().getJavaClass());
730                         }
731                         try {
732                             cachedObject = session.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(selectionCriteria, query.getReferenceClass(), translationRow, policyToUse, conforming, false, getDescriptor());
733                         } catch (QueryException exception) {// Ignore if expression too complex.
734
if (query.shouldCheckCacheOnly()) {// Throw on only cache.
735
throw exception;
736                             }
737                         }
738                     }
739                 }
740             }
741         }
742         if (conforming) {
743             // 6: If unit of work search through new objects.
744
//
745
// PERF: 3639015 - cloning the expression no longer required
746
// when using the root session
747
if (selectionCriteria != null) {
748                 selectionCriteria.getBuilder().setSession(session.getRootSession(query));
749                 selectionCriteria.getBuilder().setQueryClass(getDescriptor().getJavaClass());
750             }
751             if (cachedObject == null) {
752                 try {
753                     if (selectionKey != null) {
754                         if (!((UnitOfWorkImpl)session).shouldNewObjectsBeCached()) {
755                             cachedObject = ((UnitOfWorkImpl)session).getObjectFromNewObjects(query.getReferenceClass(), selectionKey);
756                         }
757                     } else {
758                         cachedObject = ((UnitOfWorkImpl)session).getObjectFromNewObjects(selectionCriteria, query.getReferenceClass(), translationRow, policyToUse);
759                     }
760                 } catch (QueryException exception) {
761                 }
762                 // Ignore if expression too complex.
763
}
764
765             // Finally, check that a positive result is not deleted in the Unit Of Work.
766
//
767
if (cachedObject != null) {
768                 if (((UnitOfWorkImpl)session).isObjectDeleted(cachedObject)) {
769                     if (selectionKey != null) {
770                         // In this case return a special value, to notify TopLink
771
// that the object was found but null must be returned.
772
return InvalidObject.instance;
773                     } else {
774                         cachedObject = null;
775                     }
776                 }
777             }
778         }
779
780         //fetch group check
781
if (getDescriptor().hasFetchGroupManager()) {
782             if (getDescriptor().getFetchGroupManager().isPartialObject(cachedObject)) {
783                 if (!getDescriptor().getFetchGroupManager().isObjectValidForFetchGroup(cachedObject, getReadObjectQuery().getFetchGroup())) {
784                     //the cached object is patially fetched, and it's fetch group is not a superset of the one in the query, so the cached object is not valid for the query.
785
cachedObject = null;
786                 }
787             }
788         }
789
790         return cachedObject;
791     }
792
793     /**
794      * Clone the mechanism for the specified query clone.
795      * Should not try to clone statements.
796      */

797     public DatabaseQueryMechanism clone(DatabaseQuery queryClone) {
798         DatabaseQueryMechanism clone = (DatabaseQueryMechanism)clone();
799         clone.setQuery(queryClone);
800         return clone;
801     }
802
803     /**
804      * Return an expression builder which is valid for us
805      */

806     public ExpressionBuilder getExpressionBuilder() {
807         if (getSelectionCriteria() != null) {
808             return getSelectionCriteria().getBuilder();
809         }
810         return null;
811     }
812
813     /**
814      * Return the selection criteria of the query.
815      */

816     public Expression getSelectionCriteria() {
817         return selectionCriteria;
818     }
819
820     /**
821      * Return the fields required in the select clause.
822      * This must now be called after normalization, so it will get the aliased fields
823      */

824     public Vector getSelectionFields(SQLSelectStatement statement, boolean includeAllSubclassFields) {
825         ObjectLevelReadQuery owner = (ObjectLevelReadQuery)getQuery();
826         //fetch group support
827
if (owner.hasFetchGroupAttributeExpressions()) {
828             Vector fields = new Vector(owner.getFetchGroup().getFetchGroupAttributeExpressions().size());
829             for (Iterator attrExprIter = owner.getFetchGroup().getFetchGroupAttributeExpressions().iterator();
830                      attrExprIter.hasNext();) {
831                 Expression fetchGroupAttrExpr = (Expression)attrExprIter.next();
832                 fields.add(fetchGroupAttrExpr);
833             }
834
835             // Add additional fields, use for fetch group version locking field retrieval.
836
Helper.addAllToVector(fields, owner.getAdditionalFields());
837             return fields;
838         }
839
840         ExpressionBuilder base = statement.getExpressionBuilder();
841
842         // All fields are required if all subclass field are need, this is for view selects, or where parent and children share a single table.
843
Vector fields;
844         if (includeAllSubclassFields) {
845             fields = (Vector)getDescriptor().getAllFields().clone();
846         } else {
847             fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
848             fields.addElement(base);
849         }
850
851         // Add joined fields.
852
fields.addAll(owner.getJoinedAttributeManager().getJoinedAttributeExpressions());
853         fields.addAll(owner.getJoinedAttributeManager().getJoinedMappingExpressions());
854
855         // Add additional fields, use for batch reading m-m.
856
fields.addAll(owner.getAdditionalFields());
857         return fields;
858     }
859     
860     /**
861      * Return the fields required in the from and where clause (join). These
862      * fields will not apprear in the select clause.
863      */

864     public Vector getNonSelectionFields() {
865         Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
866
867         // Add non fetch joined fields.
868
fields.addAll(((ObjectLevelReadQuery) getQuery()).getNonFetchJoinAttributeExpressions());
869         
870         return fields;
871     }
872
873     /**
874      * Return true if this is an expression query mechanism.
875      */

876     public boolean isExpressionQueryMechanism() {
877         return true;
878     }
879
880     /**
881      * Return true if this is a statement query mechanism
882      */

883     public boolean isStatementQueryMechanism() {
884         return false;
885     }
886
887     /**
888      * Override super to do nothing.
889      */

890     public void prepare() throws QueryException {
891         // Do nothing.
892
}
893
894     /**
895      * Pre-build the SQL statement from the expression.
896      */

897     public void prepareCursorSelectAllRows() {
898         if (getQuery().isReportQuery()) {
899             SQLSelectStatement statement = buildReportQuerySelectStatement(false);
900             setSQLStatement(statement);
901             // For bug 2718118 inheritance with cursors is supported provided there is a read all subclasses view.
902
} else if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().requiresMultipleTableSubclassRead() && getDescriptor().getInheritancePolicy().hasView()) {
903             InheritancePolicy inheritancePolicy = getDescriptor().getInheritancePolicy();
904             SQLSelectStatement statement = inheritancePolicy.buildViewSelectStatement((ObjectLevelReadQuery)getQuery());
905             setSQLStatement(statement);
906         } else {
907             setSQLStatement(buildNormalSelectStatement());
908         }
909
910         super.prepareCursorSelectAllRows();
911     }
912
913     /**
914      * Pre-build the SQL statement from the expression.
915      */

916     public void prepareDeleteAll() {
917         prepareDeleteAll(null);
918     }
919     
920     protected void prepareDeleteAll(Vector tablesToIgnore) {
921         Vector tablesInInsertOrder;
922         if(tablesToIgnore == null) {
923             // It's original (not a nested) method call.
924
tablesInInsertOrder = getDescriptor().getMultipleTableInsertOrder();
925         } else {
926             // It's a nested method call: tableInInsertOrder filled with descriptor's tables (in insert order),
927
// the tables found in tablesToIgnore are thrown away -
928
// they have already been taken care of by the caller.
929
tablesInInsertOrder = new Vector(getDescriptor().getMultipleTableInsertOrder().size());
930             for (Iterator tablesEnum = getDescriptor().getMultipleTableInsertOrder().iterator();
931                      tablesEnum.hasNext();) {
932                 DatabaseTable table = (DatabaseTable)tablesEnum.next();
933                 if(!tablesToIgnore.contains(table)) {
934                     tablesInInsertOrder.addElement(table);
935                 }
936             }
937         }
938         
939         if(!tablesInInsertOrder.isEmpty()) {
940             Expression whereClause = getSelectionCriteria();
941             
942             SQLCall selectCallForExist = null;
943
944             boolean isSelectCallForNotExistRequired = tablesToIgnore == null && tablesInInsertOrder.size() > 1;
945
946             SQLSelectStatement selectStatementForNotExist = null;
947             SQLCall selectCallForNotExist = null;
948             Expression inheritanceExpression = null;
949             if(getDescriptor().hasInheritance()) {
950                 if(getDescriptor().getInheritancePolicy().shouldReadSubclasses()) {
951                     inheritanceExpression = getDescriptor().getInheritancePolicy().getWithAllSubclassesExpression();
952                 } else {
953                     inheritanceExpression = getDescriptor().getInheritancePolicy().getOnlyInstancesExpression();
954                 }
955             }
956             SQLSelectStatement selectStatementForExist = createSQLSelectStatementForModifyAll(whereClause);
957             
958             // Main Case: Descriptor is mapped to more than one table and/or the query references other tables
959
boolean isMainCase = selectStatementForExist.requiresAliases();
960             if(isMainCase) {
961                 if(whereClause != null) {
962                     if(getSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll() && tablesToIgnore == null) {
963                         // currently DeleteAll using Oracle anonymous block is not implemented
964
if(!getSession().getPlatform().isOracle()) {
965                             prepareDeleteAllUsingTempStorage();
966                             return;
967                         }
968                     }
969                 
970                     selectCallForExist = (SQLCall)selectStatementForExist.buildCall(getSession());
971
972                     if(isSelectCallForNotExistRequired) {
973                         selectStatementForNotExist = createSQLSelectStatementForModifyAll(null, null);
974                         selectCallForNotExist = (SQLCall)selectStatementForNotExist.buildCall(getSession());
975                     }
976                 } else {
977                     //whereClause = null
978
if(getSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll() && tablesToIgnore == null) {
979                         // currently DeleteAll using Oracle anonymous block is not implemented
980
if(!getSession().getPlatform().isOracle()) {
981                             // there are at least two storeys of inheritance above the referenceClass
982
if(getDescriptor().hasInheritance() && getDescriptor().getTables().size() > 2) {
983                                 prepareDeleteAllUsingTempStorage();
984                                 return;
985                             }
986                         }
987                     }
988                 }
989             }
990                 
991             if(isMainCase) {
992                 // Main case: Descriptor is mapped to more than one table and/or the query references other tables
993
//
994
// Add and prepare to a call a delete statement for each table.
995
// In the case of multiple tables, build the sql statements Vector in insert order. When the
996
// actual SQL calls are sent they are sent in the reverse of this order.
997
for (Enumeration tablesEnum = tablesInInsertOrder.elements(); tablesEnum.hasMoreElements();) {
998                     DatabaseTable table = (DatabaseTable)tablesEnum.nextElement();
999                     
1000                    Collection primaryKeyFields = getPrimaryKeyFieldsForTable(table);
1001                    
1002                    SQLDeleteStatement deleteStatement;
1003
1004                    // Indicates which kind of sql call should be built:
1005
// the one containing "EXISTS" or the one containing "NOT EXISTS".
1006
// In Employee example, query with reference class:
1007
// Employee will build "EXISTS" for SALARY and "NOT EXISTS" for EMPLOYEE;
1008
// LargeProject will build "EXISTS" for LPROJECT and "NOT EXISTS" for Project
1009
boolean useSelectCallForExist = !isSelectCallForNotExistRequired || table.equals((DatabaseTable)tablesInInsertOrder.lastElement());
1010                    if(useSelectCallForExist) {
1011                        // In Employee example, query with reference class:
1012
// Employee calls this for SALARY table;
1013
// LargeProject calls this for LPROJECT table;
1014
deleteStatement = buildDeleteAllStatement(table, null, selectCallForExist, selectStatementForExist, null, null, primaryKeyFields);
1015                    } else {
1016                        if(inheritanceExpression == null) {
1017                            // In Employee example, query with reference class Employee calls this for EMPLOYEE table
1018
deleteStatement = buildDeleteAllStatement(table, null, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
1019                        } else {
1020                            if(table.equals(getDescriptor().getMultipleTableInsertOrder().firstElement())) {
1021                                // This is the highest table in inheritance hierarchy - the one that contains conditions
1022
// (usually class indicator fields) that defines the class identity.
1023
// inheritanceExpression is for this table (it doesn't reference any other tables).
1024
// In Employee example, query with reference class LargeProject calls this for PROJECT table
1025
deleteStatement = buildDeleteAllStatement(table, inheritanceExpression, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
1026                            } else {
1027                                // find the highest descriptor in inheritance hierarchy mapped to the table
1028
ClassDescriptor desc = getDescriptor();
1029                                ClassDescriptor parentDescriptor = getDescriptor().getInheritancePolicy().getParentDescriptor();
1030                                while(parentDescriptor.getTables().contains(table)) {
1031                                    desc = parentDescriptor;
1032                                    parentDescriptor = parentDescriptor.getInheritancePolicy().getParentDescriptor();
1033                                }
1034
1035                                if(desc == getDescriptor()) {
1036                                    // Class has multiple tables that are not inherited.
1037
// In extended Employee example:
1038
// Employee2 class inherits from Employee and
1039
// mapped to two additional tables: EMPLOYEE2 and SALARY2.
1040
// Query with reference class Employee2 calls this for EMPLOYEE2 table.
1041
deleteStatement = buildDeleteAllStatement(table, null, null, null, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
1042                                } else {
1043                                    // This table is mapped through descriptor that stands higher in inheritance hierarchy
1044
// (but not the highest one - this is taken care in another case).
1045
//
1046
// inheritanceSelectStatementForExist is created for the higher descriptor,
1047
// but the inheritance expression from the current descriptor is used.
1048
// Note that this trick doesn't work in case the higher descriptor was defined with
1049
// inheritance policy set not to read subclasses
1050
// (descriptor.getInheritancePolicy().dontReadSubclassesOnQueries()).
1051
// In that case inheritance expression for the higher descriptor can't
1052
// be removed - it still appears in the sql and collides with the inheritance
1053
// expression from the current descriptor - the selection expression is never true.
1054
//
1055
// In extended Employee example:
1056
// VeryLargeProject inherits from LargeProject,
1057
// mapped to an additional table VLPROJECT.
1058
// Query with reference class VeryLargeProject calls this for LPROJECT table.
1059
//
1060
// Note that this doesn't work in case LargeProject descriptor was set not to read subclasses:
1061
// in that case the selection expression will have (PROJ_TYPE = 'L') AND (PROJ_TYPE = 'V')
1062
//
1063
SQLSelectStatement inheritanceSelectStatementForExist = createSQLSelectStatementForModifyAll(null, inheritanceExpression, desc);
1064                                    SQLCall inheritanceSelectCallForExist = (SQLCall)inheritanceSelectStatementForExist.buildCall(getSession());
1065
1066                                    deleteStatement = buildDeleteAllStatement(table, null, inheritanceSelectCallForExist, inheritanceSelectStatementForExist, selectCallForNotExist, selectStatementForNotExist, primaryKeyFields);
1067                                }
1068                            }
1069                        }
1070                    }
1071        
1072                    if (getDescriptor().getTables().size() > 1) {
1073                        getSQLStatements().addElement(deleteStatement);
1074                    } else {
1075                        setSQLStatement(deleteStatement);
1076                    }
1077                }
1078            } else {
1079                // A simple case:
1080
// there is only one table mapped to the descriptor, and
1081
// selection criteria doesn't reference any other tables
1082
// A simple sql call with no subselect should be built.
1083
// In Employee example, query with reference class:
1084
// Project will build a simple sql call for PROJECT(and will make nested method calls for LargeProject and SmallProject);
1085
// SmallProject will build a simple sql call for PROJECT
1086
setSQLStatement(buildDeleteAllStatement(inheritanceExpression));
1087            }
1088
1089            // Add statements for ManyToMany and DirectCollection mappings
1090
Vector deleteStatementsForMappings = buildDeleteAllStatementsForMappings(inheritanceExpression, selectCallForExist, selectStatementForExist, tablesToIgnore == null);
1091            if(!deleteStatementsForMappings.isEmpty()) {
1092                if(getSQLStatement() != null) {
1093                    getSQLStatements().add(getSQLStatement());
1094                    setSQLStatement(null);
1095                }
1096                getSQLStatements().addAll(deleteStatementsForMappings);
1097            }
1098        }
1099
1100        // Indicates whether the descriptor has children using extra tables.
1101
boolean hasChildrenWithExtraTables = getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().hasChildren() && getDescriptor().getInheritancePolicy().hasMultipleTableChild();
1102
1103        // TBD: should we ignore subclasses in case descriptor doesn't want us to read them in?
1104
//** Currently in this code we do ignore.
1105
//** If it will be decided that we need to handle children in all cases
1106
//** the following statement should be changed to: boolean shouldHandleChildren = hasChildrenWithExtraTables;
1107
boolean shouldHandleChildren = hasChildrenWithExtraTables && getDescriptor().getInheritancePolicy().shouldReadSubclasses();
1108
1109        // Perform a nested method call for each child
1110
if(shouldHandleChildren) {
1111            // In Employee example: query for Project will make nested calls to
1112
// LargeProject and SmallProject and ask them to ignore PROJECT table
1113
Vector tablesToIgnoreForChildren = new Vector();
1114            // The tables this descriptor has ignored, its children also should ignore.
1115
if(tablesToIgnore != null) {
1116                tablesToIgnoreForChildren.addAll(tablesToIgnore);
1117            }
1118
1119            // If the desctiptor reads subclasses there is no need for
1120
// subclasses to process its tables for the second time.
1121
if (getDescriptor().getInheritancePolicy().shouldReadSubclasses()) {
1122                tablesToIgnoreForChildren.addAll(tablesInInsertOrder);
1123            }
1124            
1125            Iterator it = getDescriptor().getInheritancePolicy().getChildDescriptors().iterator();
1126            while(it.hasNext()) {
1127                // Define the same query for the child
1128
ClassDescriptor childDescriptor = (ClassDescriptor)it.next();
1129                
1130                // Need to process only "multiple tables" child descriptors
1131
if ((childDescriptor.getTables().size() > getDescriptor().getTables().size()) ||
1132                    (childDescriptor.getInheritancePolicy().hasMultipleTableChild()))
1133                {
1134                    DeleteAllQuery childQuery = new DeleteAllQuery();
1135                    childQuery.setReferenceClass(childDescriptor.getJavaClass());
1136                    childQuery.setSelectionCriteria(getSelectionCriteria());
1137                    childQuery.setDescriptor(childDescriptor);
1138                    childQuery.setSession(getSession());
1139                    
1140                    ExpressionQueryMechanism childMechanism = (ExpressionQueryMechanism)childQuery.getQueryMechanism();
1141                    // nested call
1142
childMechanism.prepareDeleteAll(tablesToIgnoreForChildren);
1143                    
1144                    // Copy the statements from child query mechanism.
1145
// In Employee example query for Project will pick up a statement for
1146
// LPROJECT table from LargeProject and nothing from SmallProject.
1147
Vector childStatements = new Vector();
1148                    if(childMechanism.getCall() != null) {
1149                        childStatements.add(childMechanism.getSQLStatement());
1150                    } else if(childMechanism.getSQLStatements() != null) {
1151                        childStatements.addAll(childMechanism.getSQLStatements());
1152                    }
1153                    if(!childStatements.isEmpty()) {
1154                        if(getSQLStatement() != null) {
1155                            getSQLStatements().add(getSQLStatement());
1156                            setSQLStatement(null);
1157                        }
1158                        getSQLStatements().addAll(childStatements);
1159                    }
1160                }
1161            }
1162        }
1163        
1164        // Nested method call doesn't need to call this.
1165
if(tablesToIgnore == null) {
1166            ((DeleteAllQuery)getQuery()).setIsPreparedUsingTempStorage(false);
1167            super.prepareDeleteAll();
1168        }
1169    }
1170
1171    protected void prepareDeleteAllUsingTempStorage() {
1172        if(getSession().getPlatform().supportsTempTables()) {
1173            prepareDeleteAllUsingTempTables();
1174        } else {
1175            throw QueryException.tempTablesNotSupported(getQuery(), Helper.getShortClassName(getSession().getPlatform()));
1176        }
1177    }
1178    
1179    protected void prepareDeleteAllUsingTempTables() {
1180        getSQLStatements().addAll(buildStatementsForDeleteAllForTempTables());
1181        ((DeleteAllQuery)getQuery()).setIsPreparedUsingTempStorage(true);
1182        super.prepareDeleteAll();
1183    }
1184    
1185    // Create SQLDeleteAllStatements for mappings that may be responsible for references
1186
// to the objects to be deleted
1187
// in the tables NOT mapped to any class: ManyToManyMapping and DirectCollectionMapping
1188
protected Vector buildDeleteAllStatementsForMappings(Expression inheritanceExpression, SQLCall selectCallForExist, SQLSelectStatement selectStatementForExist, boolean dontCheckDescriptor) {
1189        Vector deleteStatements = new Vector();
1190        Iterator itMappings = getDescriptor().getMappings().iterator();
1191        while(itMappings.hasNext()) {
1192            DatabaseMapping mapping = (DatabaseMapping)itMappings.next();
1193            if(mapping.isManyToManyMapping() || mapping.isDirectCollectionMapping()) {
1194                if(dontCheckDescriptor || mapping.getDescriptor().equals(getDescriptor())) {
1195                    Vector sourceFields = null;
1196                    Vector targetFields = null;
1197                    if(mapping.isManyToManyMapping()) {
1198                        sourceFields = ((ManyToManyMapping)mapping).getSourceKeyFields();
1199                        targetFields = ((ManyToManyMapping)mapping).getSourceRelationKeyFields();
1200                    } else if(mapping.isDirectCollectionMapping()) {
1201                        sourceFields = ((DirectCollectionMapping)mapping).getSourceKeyFields();
1202                        targetFields = ((DirectCollectionMapping)mapping).getReferenceKeyFields();
1203                    }
1204                    if(selectCallForExist == null) {
1205                        if(inheritanceExpression != null || getSelectionCriteria() != null) {
1206                            selectCallForExist = (SQLCall)selectStatementForExist.buildCall(getSession());
1207                        }
1208                    }
1209                    deleteStatements.addElement(buildSQLDeleteAllStatementForMapping(selectCallForExist, selectStatementForExist, sourceFields, targetFields));
1210                }
1211            }
1212        }
1213        return deleteStatements;
1214    }
1215    
1216    protected SQLSelectStatement createSQLSelectStatementForModifyAll(Expression whereClause) {
1217        return createSQLSelectStatementForModifyAll(whereClause, null, getDescriptor(), false);
1218    }
1219    
1220    protected SQLSelectStatement createSQLSelectStatementForModifyAll(Expression whereClause, Expression inheritanceExpression) {
1221        return createSQLSelectStatementForModifyAll(whereClause, inheritanceExpression, getDescriptor(), true);
1222    }
1223    
1224    protected SQLSelectStatement createSQLSelectStatementForModifyAll(Expression whereClause, Expression inheritanceExpression,
1225                                 ClassDescriptor desc)
1226    {
1227        return createSQLSelectStatementForModifyAll(whereClause, inheritanceExpression, desc, true);
1228    }
1229    
1230    protected SQLSelectStatement createSQLSelectStatementForModifyAll(Expression whereClause, Expression inheritanceExpression,
1231                                 ClassDescriptor desc, boolean useCustomaryInheritanceExpression)
1232    {
1233        ExpressionBuilder builder;
1234        if(whereClause != null) {
1235            whereClause = (Expression)whereClause.clone();
1236            builder = whereClause.getBuilder();
1237        } else {
1238            builder = new ExpressionBuilder();
1239        }
1240        
1241        ReportQuery reportQuery = new ReportQuery(desc.getJavaClass(), builder);
1242        reportQuery.setDescriptor(desc);
1243        reportQuery.setShouldRetrieveFirstPrimaryKey(true);
1244        reportQuery.setSelectionCriteria(whereClause);
1245        reportQuery.setSession(getSession());
1246        
1247        return ((ExpressionQueryMechanism)reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false, useCustomaryInheritanceExpression, inheritanceExpression);
1248    }
1249        
1250    protected SQLSelectStatement createSQLSelectStatementForAssignedExpressionForUpdateAll(Expression value)
1251    {
1252        ReportQuery reportQuery = new ReportQuery(getQuery().getReferenceClass(), value.getBuilder());
1253        reportQuery.setDescriptor(getQuery().getDescriptor());
1254        reportQuery.setSession(getSession());
1255        reportQuery.addAttribute("", value);
1256        
1257        return ((ExpressionQueryMechanism)reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false);
1258    }
1259        
1260    /**
1261     * Pre-build the SQL statement from the expression.
1262     */

1263    public void prepareDeleteObject() {
1264        // Add and prepare to a call a delete statement for each table.
1265
// In the case of multiple tables, build the sql statements Vector in insert order. When the
1266
// actual SQL calls are sent they are sent in the reverse of this order.
1267
for (Enumeration tablesEnum = getDescriptor().getMultipleTableInsertOrder().elements();
1268                 tablesEnum.hasMoreElements();) {
1269            DatabaseTable table = (DatabaseTable)tablesEnum.nextElement();
1270            SQLDeleteStatement deleteStatement = buildDeleteStatement(table);
1271            if (getDescriptor().getTables().size() > 1) {
1272                getSQLStatements().addElement(deleteStatement);
1273            } else {
1274                setSQLStatement(deleteStatement);
1275            }
1276        }
1277
1278        super.prepareDeleteObject();
1279    }
1280
1281    /**
1282     * Pre-build the SQL statement from the expression.
1283     */

1284    public void prepareDoesExist(DatabaseField field) {
1285        setSQLStatement(buildSelectStatementForDoesExist(field));
1286
1287        super.prepareDoesExist(field);
1288    }
1289
1290    /**
1291     * Pre-build the SQL statement from the expression.
1292     */

1293    public void prepareInsertObject() {
1294        // Require modify row to prepare.
1295
if (getModifyRow() == null) {
1296            return;
1297        }
1298
1299        // Add and prepare to a call a update statement for each table.
1300
// In the case of multiple tables, build the sql statements Vector in insert order.
1301
for (Enumeration tablesEnum = getDescriptor().getMultipleTableInsertOrder().elements();
1302                 tablesEnum.hasMoreElements();) {
1303            DatabaseTable table = (DatabaseTable)tablesEnum.nextElement();
1304            SQLInsertStatement insertStatement = buildInsertStatement(table);
1305            if (getDescriptor().getTables().size() > 1) {
1306                getSQLStatements().addElement(insertStatement);
1307            } else {
1308                setSQLStatement(insertStatement);
1309            }
1310        }
1311
1312        super.prepareInsertObject();
1313    }
1314
1315    /**
1316     * Pre-build the SQL statement from the expression.
1317     */

1318    public void prepareReportQuerySelectAllRows() {
1319        SQLSelectStatement statement = buildReportQuerySelectStatement(false);
1320        setSQLStatement(statement);
1321        setCallFromStatement();
1322        // The statement is no longer require so can be released.
1323
setSQLStatement(null);
1324
1325        getCall().returnManyRows();
1326        prepareCall();
1327    }
1328
1329    /**
1330     * Pre-build the SQL statement from the expression.
1331     * This is used for subselects, so does not normalize or generate the SQL as it needs the outer expression for this.
1332     */

1333    public void prepareReportQuerySubSelect() {
1334        setSQLStatement(buildReportQuerySelectStatement(true));
1335        // The expression is no longer require so can be released.
1336
setSelectionCriteria(null);
1337    }
1338
1339    /**
1340     * Pre-build the SQL statement from the expression.
1341     */

1342    public void prepareSelectAllRows() {
1343        if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().requiresMultipleTableSubclassRead()) {
1344            if (getDescriptor().getInheritancePolicy().hasView()) {
1345                // CR#3158703 if the descriptor has a view, then it requires a single select,
1346
// so can be prepared.
1347
setSQLStatement(getDescriptor().getInheritancePolicy().buildViewSelectStatement((ObjectLevelReadQuery)getQuery()));
1348                super.prepareSelectAllRows();
1349            } else if (!getDescriptor().getInheritancePolicy().hasClassExtractor()) {
1350                // CR#3158703 otherwise if using a type indicator at least the type select can be prepared.
1351
setSQLStatement(getDescriptor().getInheritancePolicy().buildClassIndicatorSelectStatement((ObjectLevelReadQuery)getQuery()));
1352                super.prepareSelectAllRows();
1353            }
1354
1355            // else - otherwise cannot prepare the select.
1356
} else {
1357            setSQLStatement(buildNormalSelectStatement());
1358            super.prepareSelectAllRows();
1359        }
1360    }
1361
1362    /**
1363     * Pre-build the SQL statement from the expression.
1364     */

1365    public void prepareSelectOneRow() {
1366        if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().requiresMultipleTableSubclassRead()) {
1367            if (getDescriptor().getInheritancePolicy().hasView()) {
1368                // CR#3158703 if the descriptor has a view, then it requires a single select,
1369
// so can be prepared.
1370
setSQLStatement(getDescriptor().getInheritancePolicy().buildViewSelectStatement((ObjectLevelReadQuery)getQuery()));
1371                super.prepareSelectOneRow();
1372            } else if (!getDescriptor().getInheritancePolicy().hasClassExtractor()) {
1373                // CR#3158703 otherwise if using a type indicator at least the type select can be prepared.
1374
setSQLStatement(getDescriptor().getInheritancePolicy().buildClassIndicatorSelectStatement((ObjectLevelReadQuery)getQuery()));
1375                super.prepareSelectOneRow();
1376            }
1377
1378            // else - otherwise cannot prepare the select.
1379
} else {
1380            setSQLStatement(buildNormalSelectStatement());
1381            super.prepareSelectOneRow();
1382        }
1383    }
1384
1385    /**
1386     * Pre-build the SQL statement from the expression.
1387     */

1388    public void prepareUpdateObject() {
1389        // Require modify row to prepare.
1390
if (getModifyRow() == null) {
1391            return;
1392        }
1393
1394        // Add and prepare to a call a update statement for each table.
1395
int tablesSize = getDescriptor().getTables().size();
1396        for (int index = 0; index < tablesSize; index++) {
1397            DatabaseTable table = (DatabaseTable)getDescriptor().getTables().get(index);
1398            SQLUpdateStatement updateStatement = buildUpdateStatement(table);
1399            if (tablesSize > 1) {
1400                getSQLStatements().addElement(updateStatement);
1401            } else {
1402                setSQLStatement(updateStatement);
1403            }
1404        }
1405
1406        super.prepareUpdateObject();
1407    }
1408
1409    /**
1410     * Pre-build the SQL statement from the expressions.
1411     */

1412    public void prepareUpdateAll() {
1413        ExpressionBuilder builder = ((UpdateAllQuery)getQuery()).getExpressionBuilder();
1414        HashMap updateClauses = ((UpdateAllQuery)getQuery()).getUpdateClauses();
1415        
1416        // Add a statement to update the optimistic locking field if their is one.
1417
OptimisticLockingPolicy policy = getDescriptor().getOptimisticLockingPolicy();
1418        if (policy != null) {
1419            if(policy.getWriteLockField() != null) {
1420                Expression writeLock = builder.getField(policy.getWriteLockField());
1421                Expression writeLockUpdateExpression = policy.getWriteLockUpdateExpression(builder);
1422                if (writeLockUpdateExpression != null) {
1423                    // clone it to keep user's original data intact
1424
updateClauses = (HashMap)updateClauses.clone();
1425                    updateClauses.put(writeLock, writeLockUpdateExpression);
1426                }
1427            }
1428        }
1429        
1430        HashMap tables_databaseFieldsToValues = new HashMap();
1431        HashMap tablesToPrimaryKeyFields = new HashMap();
1432        Iterator it = updateClauses.entrySet().iterator();
1433        while(it.hasNext()) {
1434            Map.Entry entry = (Map.Entry)it.next();
1435            
1436            Object JavaDoc fieldObject = entry.getKey();
1437            DataExpression fieldExpression = null;
1438            String JavaDoc attributeName = null;
1439            if(fieldObject instanceof String JavaDoc) {
1440                attributeName = (String JavaDoc)fieldObject;
1441            } else {
1442                // it should be either QueryKeyExpression or FieldExpression
1443
fieldExpression = (DataExpression)fieldObject;
1444            }
1445
1446            DatabaseField field = null;
1447            DatabaseMapping mapping = null;
1448            if(attributeName != null) {
1449                mapping = getDescriptor().getObjectBuilder().getMappingForAttributeName(attributeName);
1450                if (mapping != null && !mapping.getFields().isEmpty()) {
1451                    field = (DatabaseField)mapping.getFields().firstElement();
1452                }
1453                if(field == null) {
1454                    throw QueryException.updateAllQueryAddUpdateDoesNotDefineField(getDescriptor(), getQuery(), attributeName);
1455                }
1456            } else if (fieldExpression != null) {
1457                field = getDescriptor().getObjectBuilder().getFieldForQueryKeyName(fieldExpression.getName());
1458                if(field == null) {
1459                    DataExpression fieldExpressionClone = (DataExpression)fieldExpression.clone();
1460                    fieldExpressionClone.getBuilder().setQueryClass(getQuery().getReferenceClass());
1461                    fieldExpressionClone.getBuilder().setSession(getSession());
1462                    field = fieldExpressionClone.getField();
1463                    if(field == null) {
1464                        throw QueryException.updateAllQueryAddUpdateDoesNotDefineField(getDescriptor(), getQuery(), fieldExpression.toString());
1465                    }
1466                }
1467                mapping = getDescriptor().getObjectBuilder().getMappingForField(field);
1468            }
1469
1470            Object JavaDoc valueObject = entry.getValue();
1471            Vector fields;
1472            Vector values;
1473            if(mapping != null && mapping.isOneToOneMapping()) {
1474                fields = mapping.getFields();
1475                int fieldsSize = fields.size();
1476                values = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldsSize);
1477                for(int i=0; i<fieldsSize; i++) {
1478                    if(valueObject instanceof ConstantExpression) {
1479                        valueObject = ((ConstantExpression)valueObject).getValue();
1480                    }
1481                    if(valueObject == null) {
1482                        values.add(null);
1483                    } else {
1484                        DatabaseField targetField = (DatabaseField)((OneToOneMapping)mapping).getSourceToTargetKeyFields().get(fields.elementAt(i));
1485                        if(valueObject instanceof Expression) {
1486                            values.add(((Expression)((Expression)valueObject).clone()).getField(targetField));
1487                        } else {
1488                            values.add(((OneToOneMapping)mapping).getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(valueObject, targetField, getSession()));
1489                        }
1490                    }
1491                }
1492            } else {
1493                fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1);
1494                fields.add(field);
1495                values = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1);
1496                values.add(valueObject);
1497            }
1498            int fieldsSize = fields.size();
1499            for(int i=0; i<fieldsSize; i++) {
1500                field = (DatabaseField)fields.elementAt(i);
1501                DatabaseTable table = field.getTable();
1502                if(!getDescriptor().getTables().contains(table)) {
1503                    if(attributeName != null) {
1504                        throw QueryException.updateAllQueryAddUpdateDefinesWrongField(getDescriptor(), getQuery(), attributeName, field.getQualifiedName());
1505                    } else {
1506                        throw QueryException.updateAllQueryAddUpdateDefinesWrongField(getDescriptor(), getQuery(), fieldExpression.toString(), field.getQualifiedName());
1507                    }
1508                }
1509                
1510                HashMap databaseFieldsToValues = (HashMap)tables_databaseFieldsToValues.get(table);
1511                if(databaseFieldsToValues == null) {
1512                    databaseFieldsToValues = new HashMap();
1513                    tables_databaseFieldsToValues.put(table, databaseFieldsToValues);
1514    
1515                    tablesToPrimaryKeyFields.put(table, getPrimaryKeyFieldsForTable(table));
1516                }
1517    
1518                Object JavaDoc value = values.elementAt(i);
1519                Expression valueExpression;
1520                if(valueObject instanceof Expression) {
1521                    valueExpression = (Expression)value;
1522                } else {
1523                    valueExpression = builder.value(value);
1524                }
1525                
1526                databaseFieldsToValues.put(field, valueExpression);
1527            }
1528        }
1529        
1530        SQLCall selectCallForExist = null;
1531        SQLSelectStatement selectStatementForExist = createSQLSelectStatementForModifyAll(getSelectionCriteria());
1532        
1533        // Main Case: Descriptor is mapped to more than one table and/or the query references other tables
1534
boolean isMainCase = selectStatementForExist.requiresAliases();
1535        if(isMainCase && getSelectionCriteria() != null) {
1536            if(getSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll()) {
1537                prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
1538                return;
1539            }
1540            selectCallForExist = (SQLCall)selectStatementForExist.buildCall(getSession());
1541        }
1542        
1543        // ExpressionIterator to search for valueExpressions that require select statements.
1544
// Those are expressions that
1545
// either reference other tables:
1546
// Employee-based example: valueExp = builder.get("address").get("city");
1547
// or use DataExpressions with base not ExpressionBuilder:
1548
// Employee-base example: valueExp = builder.get("manager").get("firstName");
1549
// Before iterating the table is set into result,
1550
// if expression requiring select is found, then resul set to null.
1551
ExpressionIterator expRequiresSelectIterator = new ExpressionIterator() {
1552            public void iterate(Expression each) {
1553                if(getResult() == null) {
1554                    return;
1555                }
1556                if(each instanceof DataExpression) {
1557                    DataExpression dataExpression = (DataExpression)each;
1558                    Expression baseExpression = dataExpression.getBaseExpression();
1559                    if(baseExpression != null && !(baseExpression instanceof ExpressionBuilder)) {
1560                        boolean stop = true;
1561                        if(baseExpression instanceof DataExpression) {
1562                            DataExpression baseDataExpression = (DataExpression)baseExpression;
1563                            if(baseDataExpression.getMapping() != null && baseDataExpression.getMapping().isAggregateObjectMapping()) {
1564                                stop = false;
1565                            }
1566                        }
1567                        if(stop) {
1568                            setResult(null);
1569                            return;
1570                        }
1571                    }
1572                    DatabaseField field = dataExpression.getField();
1573                    if(field != null) {
1574                        if(!field.getTable().equals((DatabaseTable)getResult())) {
1575                            setResult(null);
1576                            return;
1577                        }
1578                    }
1579                }
1580            }
1581            public boolean shouldIterateOverSubSelects() {
1582                return true;
1583            }
1584        };
1585
1586        HashMap tables_databaseFieldsToValuesCopy = new HashMap();
1587        it = tables_databaseFieldsToValues.entrySet().iterator();
1588        while(it.hasNext()) {
1589            Map.Entry entry = (Map.Entry)it.next();
1590            DatabaseTable table = (DatabaseTable)entry.getKey();
1591            HashMap databaseFieldsToValues = (HashMap)entry.getValue();
1592            HashMap databaseFieldsToValuesCopy = new HashMap();
1593            tables_databaseFieldsToValuesCopy.put(table, databaseFieldsToValuesCopy);
1594            Iterator itFieldsToValues = databaseFieldsToValues.entrySet().iterator();
1595            while(itFieldsToValues.hasNext()) {
1596                Map.Entry entry2 = (Map.Entry)itFieldsToValues.next();
1597                DatabaseField field = (DatabaseField)entry2.getKey();
1598                Expression value = (Expression)entry2.getValue();
1599
1600                // initialize result with the table
1601
expRequiresSelectIterator.setResult(table);
1602                // To find fields have to have session and ref class
1603
Expression valueClone = (Expression)value.clone();
1604                valueClone.getBuilder().setSession(getSession());
1605                valueClone.getBuilder().setQueryClass(getQuery().getReferenceClass());
1606                expRequiresSelectIterator.iterateOn(valueClone);
1607                if(expRequiresSelectIterator.getResult() == null) {
1608                    // this one should use SELECT as an assigned expression.
1609
// The corresponding SelectionStatement should be assigned to value
1610
if(getSession().getPlatform().shouldAlwaysUseTempStorageForModifyAll()) {
1611                        prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
1612                        return;
1613                    }
1614                    
1615                    SQLSelectStatement selStatement = createSQLSelectStatementForAssignedExpressionForUpdateAll(value);
1616                    databaseFieldsToValuesCopy.put(field, selStatement);
1617                } else {
1618                    databaseFieldsToValuesCopy.put(field, valueClone);
1619                }
1620            }
1621        }
1622        HashMap tables_databaseFieldsToValuesOriginal = tables_databaseFieldsToValues;
1623        tables_databaseFieldsToValues = tables_databaseFieldsToValuesCopy;
1624        
1625        if(tables_databaseFieldsToValues.size() == 1) {
1626            Map.Entry entry = (Map.Entry)tables_databaseFieldsToValues.entrySet().iterator().next();
1627            DatabaseTable table = (DatabaseTable)entry.getKey();
1628            HashMap databaseFieldsToValues = (HashMap)entry.getValue();
1629            Collection primaryKeyFields = (Collection)tablesToPrimaryKeyFields.values().iterator().next();
1630            setSQLStatement(buildUpdateAllStatement(table, databaseFieldsToValues, selectCallForExist, selectStatementForExist, primaryKeyFields));
1631        } else {
1632            // To figure out the order of statements we need to find dependencies
1633
// between updating of tables.
1634
// Here's an example:
1635
// All objects with nameA = "Clob" should be changed so that nameA = "Alex" and nameB = "Bob";
1636
// nameA is mapped to A.name and nameB mapped to B.name:
1637
// UPDATE B SET B.name = "Bob" WHERE A.name = "Clob" and A.id = B.id;
1638
// UPDATE A SET A.name = "Alex" WHERE A.name = "Clob" and A.id = B.id;
1639
// The order can't be altered - or there will be no updating of B.
1640
// To formalize that: for each table we'll gather two Collections:
1641
// leftFields - all the table's fields to receive a new value;
1642
// rightFields - all the fields either in assigned or selecton expression.
1643
// A_leftFields = {A.name}; A_rightFields = {A.name}.
1644
// B_leftFields = {B.name}; B_rightFields = {A.name}.
1645
// There are several comparison outcomes:
1646
// 1. A_leftFields doesn't intersect B_rightFields and
1647
// B_leftFields doesn't intersect A_rightFields
1648
// There is no dependency - doesn't matter which update goes first;
1649
// 2. A_leftFields intersects B_rightFields and
1650
// B_leftFields doesn't intersect A_rightFields
1651
// B should be updated before A (the case in the example).
1652
// 3. A_leftFields intersects B_rightFields and
1653
// B_leftFields intersects A_rightFields
1654
// Ordering conflict that can't be resolved without using transitionary storage.
1655
//
1656
// This ExpressionIterator will be used for collecting fields from
1657
// selection criteria and assigned expressions.
1658
ExpressionIterator expIterator = new ExpressionIterator() {
1659                public void iterate(Expression each) {
1660                    if(each instanceof DataExpression) {
1661                        DataExpression dataExpression = (DataExpression)each;
1662                        DatabaseField field = dataExpression.getField();
1663                        if(field != null) {
1664                            ((Collection)getResult()).add(field);
1665                        }
1666                    }
1667                }
1668                public boolean shouldIterateOverSubSelects() {
1669                    return true;
1670                }
1671            };
1672            
1673            // This will hold collection of fields from selection criteria expression.
1674
HashSet selectCallForExistFields = new HashSet();
1675            if(selectCallForExist != null) {
1676                expIterator.setResult(selectCallForExistFields);
1677                expIterator.iterateOn(selectStatementForExist.getWhereClause());
1678            }
1679            
1680            // Left of the assignment operator that is - the fields acquiring new values
1681
HashMap tablesToLeftFields = new HashMap();
1682            // The fields right of the assignment operator AND the fields from whereClause
1683
HashMap tablesToRightFields = new HashMap();
1684            
1685            // before and after vectors work together: n-th member of beforeTable should
1686
// be updated before than n-th member of afterTable
1687
Vector beforeTables = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
1688            Vector afterTables = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
1689            
1690            // Both keys and values are tables.
1691
// An entry indicates a timing conflict between the key and the value:
1692
// both key should be updated before value and value before key.
1693
HashMap simpleConflicts = new HashMap();
1694            
1695            it = tables_databaseFieldsToValues.entrySet().iterator();
1696            while(it.hasNext()) {
1697                Map.Entry entry = (Map.Entry)it.next();
1698                // for each table to be updated
1699
DatabaseTable table = (DatabaseTable)entry.getKey();
1700                // here's a Map of left hand fields to right hand expressions
1701
HashMap databaseFieldsToValues = (HashMap)entry.getValue();
1702                
1703                // This will contain all the left hand fields
1704
HashSet leftFields = new HashSet(databaseFieldsToValues.size());
1705                // This will contain all the left hand fields plus fields form selection criteria
1706
HashSet rightFields = (HashSet)selectCallForExistFields.clone();
1707                expIterator.setResult(rightFields);
1708                Iterator itDatabaseFieldsToValues = databaseFieldsToValues.entrySet().iterator();
1709                while(itDatabaseFieldsToValues.hasNext()) {
1710                    // for each left hand - right hand expression pair
1711
Map.Entry databaseFieldValueEntry = (Map.Entry)itDatabaseFieldsToValues.next();
1712                    // here's the left hand database field
1713
DatabaseField field = (DatabaseField)databaseFieldValueEntry.getKey();
1714                    leftFields.add(field);
1715                    // here's the right hand expression
1716
Object JavaDoc value = databaseFieldValueEntry.getValue();
1717                    if(value instanceof Expression) {
1718                        Expression valueExpression = (Expression)value;
1719                        // use iterator to extract all the fields
1720
expIterator.iterateOn(valueExpression);
1721                    } else {
1722                        // It should be SQLSelectStatement with a single field
1723
SQLSelectStatement selStatement = (SQLSelectStatement)value;
1724                        // first one is the normalized value to be assigned
1725
expIterator.iterateOn((Expression)selStatement.getFields().elementAt(0));
1726                        // whereClause - generated during normalization
1727
expIterator.iterateOn(selStatement.getWhereClause());
1728                    }
1729                }
1730                
1731                // now let's compare the table with the already processed tables
1732
Iterator itProcessedTables = tablesToLeftFields.keySet().iterator();
1733                while(itProcessedTables.hasNext()) {
1734                    DatabaseTable processedTable = (DatabaseTable)itProcessedTables.next();
1735                    HashSet processedTableLeftFields = (HashSet)tablesToLeftFields.get(processedTable);
1736                    HashSet processedTableRightFields = (HashSet)tablesToRightFields.get(processedTable);
1737                    boolean tableBeforeProcessedTable = false;
1738                    Iterator itProcessedTableLeftField = processedTableLeftFields.iterator();
1739                    while(itProcessedTableLeftField.hasNext()) {
1740                        if(rightFields.contains(itProcessedTableLeftField.next())) {
1741                            tableBeforeProcessedTable = true;
1742                            break;
1743                        }
1744                    }
1745                    boolean processedTableBeforeTable = false;
1746                    Iterator itLeftField = leftFields.iterator();
1747                    while(itLeftField.hasNext()) {
1748                        if(processedTableRightFields.contains(itLeftField.next())) {
1749                            processedTableBeforeTable = true;
1750                            break;
1751                        }
1752                    }
1753                    if(tableBeforeProcessedTable && !processedTableBeforeTable) {
1754                        // table should be updated before processedTable
1755
beforeTables.add(table);
1756                        afterTables.add(processedTable);
1757                    } else if (!tableBeforeProcessedTable && processedTableBeforeTable) {
1758                        // processedTable should be updated before table
1759
beforeTables.add(processedTable);
1760                        afterTables.add(table);
1761                    } else if (tableBeforeProcessedTable && processedTableBeforeTable) {
1762                        // there is an order conflict between table and processTable
1763
simpleConflicts.put(processedTable, table);
1764                    }
1765                }
1766                
1767                tablesToLeftFields.put(table, leftFields);
1768                tablesToRightFields.put(table, rightFields);
1769            }
1770            
1771            if(!simpleConflicts.isEmpty()) {
1772                prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValuesOriginal, tablesToPrimaryKeyFields);
1773                return;
1774            }
1775            
1776            // This will contain tables in update order
1777
Vector orderedTables = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(tables_databaseFieldsToValues.size());
1778            // first process the tables found in beforeTables / afterTables
1779
while(!beforeTables.isEmpty()) {
1780                // Find firstTable - the one that appears in beforeTables, but not afterTables.
1781
// That means there is no requirement to update it after any other table and we
1782
// can put it first in update order. There could be several such tables -
1783
// it doesn't matter which one will be picked.
1784
DatabaseTable firstTable = null;
1785                for(int i=0; i < beforeTables.size(); i++) {
1786                    DatabaseTable beforeTable = (DatabaseTable)beforeTables.elementAt(i);
1787                    if(!afterTables.contains(beforeTable)) {
1788                        firstTable = beforeTable;
1789                        break;
1790                    }
1791                }
1792                if(firstTable == null) {
1793                    // There is no firstTable - it's an order conflict between three or more tables
1794
prepareUpdateAllUsingTempStorage(tables_databaseFieldsToValuesOriginal, tablesToPrimaryKeyFields);
1795                    return;
1796                } else {
1797                    // Remove first table from beforeTables - there could be several entries.
1798
// Also remove the corresponding entries from afterTable.
1799
for(int i=beforeTables.size()-1; i>=0; i--) {
1800                        if(beforeTables.elementAt(i).equals(firstTable)) {
1801                            beforeTables.remove(i);
1802                            afterTables.remove(i);
1803                        }
1804                    }
1805                    // Add firstTable to orderedTables
1806
orderedTables.addElement(firstTable);
1807                }
1808            }
1809
1810            // now all the remaining ones - there are no dependencies between them
1811
// so the order is arbitrary.
1812
Iterator itTables = tables_databaseFieldsToValues.keySet().iterator();
1813            while(itTables.hasNext()) {
1814                DatabaseTable table = (DatabaseTable)itTables.next();
1815                if(!orderedTables.contains(table)) {
1816                    orderedTables.add(table);
1817                }
1818            }
1819            
1820            // finally create statements
1821
for(int i=0; i < orderedTables.size(); i++) {
1822                DatabaseTable table = (DatabaseTable)orderedTables.elementAt(i);
1823                HashMap databaseFieldsToValues = (HashMap)tables_databaseFieldsToValues.get(table);
1824                Collection primaryKeyFields = (Collection)tablesToPrimaryKeyFields.get(table);
1825                getSQLStatements().addElement(buildUpdateAllStatement(table, databaseFieldsToValues, selectCallForExist, selectStatementForExist, primaryKeyFields));
1826            }
1827        }
1828
1829        ((UpdateAllQuery)getQuery()).setIsPreparedUsingTempStorage(false);
1830        super.prepareUpdateAll();
1831    }
1832
1833    protected SQLSelectStatement createSQLSelectStatementForUpdateAllForOracleAnonymousBlock(HashMap tables_databaseFieldsToValues)
1834    {
1835        ExpressionBuilder builder = ((UpdateAllQuery)getQuery()).getExpressionBuilder();
1836        Expression whereClause = getSelectionCriteria();
1837        if(whereClause != null) {
1838            whereClause = (Expression)whereClause.clone();
1839        }
1840        
1841        ReportQuery reportQuery = new ReportQuery(getDescriptor().getJavaClass(), builder);
1842        reportQuery.setDescriptor(getDescriptor());
1843        reportQuery.setSelectionCriteria(whereClause);
1844        reportQuery.setSession(getSession());
1845        
1846        reportQuery.setShouldRetrievePrimaryKeys(true);
1847        Iterator itDatabaseFieldsToValues = tables_databaseFieldsToValues.values().iterator();
1848        while(itDatabaseFieldsToValues.hasNext()) {
1849            HashMap databaseFieldsToValues = (HashMap)itDatabaseFieldsToValues.next();
1850            Iterator itValues = databaseFieldsToValues.values().iterator();
1851            while(itValues.hasNext()) {
1852                reportQuery.addAttribute("", (Expression)itValues.next());
1853            }
1854        }
1855
1856        return ((ExpressionQueryMechanism)reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false);
1857    }
1858        
1859    protected SQLSelectStatement createSQLSelectStatementForModifyAllForTempTable(HashMap databaseFieldsToValues)
1860    {
1861        ExpressionBuilder builder = ((ModifyAllQuery)getQuery()).getExpressionBuilder();
1862        Expression whereClause = getSelectionCriteria();
1863        if(whereClause != null) {
1864            whereClause = (Expression)whereClause.clone();
1865        }
1866        
1867        ReportQuery reportQuery = new ReportQuery(getDescriptor().getJavaClass(), builder);
1868        reportQuery.setDescriptor(getDescriptor());
1869        reportQuery.setSelectionCriteria(whereClause);
1870        reportQuery.setSession(getSession());
1871        
1872        reportQuery.setShouldRetrievePrimaryKeys(true);
1873        if(databaseFieldsToValues != null) {
1874            Iterator itValues = databaseFieldsToValues.values().iterator();
1875            while(itValues.hasNext()) {
1876                reportQuery.addAttribute("", (Expression)itValues.next());
1877            }
1878        }
1879
1880        return ((ExpressionQueryMechanism)reportQuery.getQueryMechanism()).buildReportQuerySelectStatement(false);
1881    }
1882        
1883    protected SQLModifyStatement buildUpdateAllStatementForOracleAnonymousBlock(HashMap tables_databaseFieldsToValues, HashMap tablesToPrimaryKeyFields) {
1884        SQLSelectStatement selectStatement = createSQLSelectStatementForUpdateAllForOracleAnonymousBlock(tables_databaseFieldsToValues);
1885        SQLCall selectCall = (SQLCall)selectStatement.buildCall(getSession());
1886        
1887        SQLUpdateAllStatementForOracleAnonymousBlock updateAllStatement = new SQLUpdateAllStatementForOracleAnonymousBlock();
1888        updateAllStatement.setTranslationRow(getTranslationRow());
1889
1890        updateAllStatement.setSelectCall(selectCall);
1891        updateAllStatement.setTables_databaseFieldsToValues(tables_databaseFieldsToValues);
1892        updateAllStatement.setTablesToPrimaryKeyFields(tablesToPrimaryKeyFields);
1893        
1894        updateAllStatement.setTable((DatabaseTable)getDescriptor().getTables().firstElement());
1895
1896        return updateAllStatement;
1897    }
1898    
1899    protected void prepareUpdateAllUsingTempStorage(HashMap tables_databaseFieldsToValues, HashMap tablesToPrimaryKeyFields) {
1900        if(getSession().getPlatform().supportsTempTables()) {
1901            prepareUpdateAllUsingTempTables(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
1902        } else if(getSession().getPlatform().isOracle()) {
1903            prepareUpdateAllUsingOracleAnonymousBlock(tables_databaseFieldsToValues, tablesToPrimaryKeyFields);
1904        } else {
1905            throw QueryException.tempTablesNotSupported(getQuery(), Helper.getShortClassName(getSession().getPlatform()));
1906        }
1907    }
1908    
1909    /**
1910     * Pre-build the SQL statement from the expressions.
1911     */

1912    protected void prepareUpdateAllUsingOracleAnonymousBlock(HashMap tables_databaseFieldsToValues, HashMap tablesToPrimaryKeyFields) {
1913        
1914        setSQLStatement(buildUpdateAllStatementForOracleAnonymousBlock(tables_databaseFieldsToValues, tablesToPrimaryKeyFields));
1915        ((UpdateAllQuery)getQuery()).setIsPreparedUsingTempStorage(true);
1916        super.prepareUpdateAll();
1917    }
1918
1919    /**
1920     * Pre-build the SQL statement from the expressions.
1921     */

1922    protected void prepareUpdateAllUsingTempTables(HashMap tables_databaseFieldsToValues, HashMap tablesToPrimaryKeyFields) {
1923        int nTables = tables_databaseFieldsToValues.size();
1924        Vector createTableStatements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(nTables);
1925        Vector selectStatements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(nTables);
1926        Vector updateStatements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(nTables);
1927        Vector cleanupStatements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(nTables);
1928        
1929        Iterator itEntrySets = tables_databaseFieldsToValues.entrySet().iterator();
1930        while(itEntrySets.hasNext()) {
1931            Map.Entry entry = (Map.Entry)itEntrySets.next();
1932            DatabaseTable table = (DatabaseTable)entry.getKey();
1933            HashMap databaseFieldsToValues = (HashMap)entry.getValue();
1934            Collection primaryKeyFields = (Collection)tablesToPrimaryKeyFields.get(table);
1935
1936            Vector statementsForTable = buildStatementsForUpdateAllForTempTables(table, databaseFieldsToValues, primaryKeyFields);
1937            
1938            createTableStatements.add(statementsForTable.elementAt(0));
1939            selectStatements.add(statementsForTable.elementAt(1));
1940            updateStatements.add(statementsForTable.elementAt(2));
1941            cleanupStatements.add(statementsForTable.elementAt(3));
1942        }
1943        
1944        getSQLStatements().addAll(createTableStatements);
1945        getSQLStatements().addAll(selectStatements);
1946        getSQLStatements().addAll(updateStatements);
1947        getSQLStatements().addAll(cleanupStatements);
1948
1949        if(getSession().getPlatform().dontBindUpdateAllQueryUsingTempTables()) {
1950            if(getQuery().shouldBindAllParameters() || (getQuery().shouldIgnoreBindAllParameters() && getSession().getPlatform().shouldBindAllParameters())) {
1951                getQuery().setShouldBindAllParameters(false);
1952                getSession().warning("update_all_query_cannot_use_binding_on_this_platform", SessionLog.QUERY);
1953            }
1954        }
1955        ((UpdateAllQuery)getQuery()).setIsPreparedUsingTempStorage(true);
1956        super.prepareUpdateAll();
1957    }
1958
1959    protected Vector buildStatementsForDeleteAllForTempTables() {
1960        Vector statements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
1961        
1962        DatabaseTable rootTable = (DatabaseTable)getDescriptor().getMultipleTableInsertOrder().firstElement();
1963        Collection rootTablePrimaryKeyFields = getPrimaryKeyFieldsForTable(rootTable);
1964        ClassDescriptor rootDescriptor = getDescriptor();
1965        if(getDescriptor().hasInheritance()) {
1966            rootDescriptor = rootDescriptor.getInheritancePolicy().getRootParentDescriptor();
1967        }
1968        Vector allFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
1969        Iterator it = rootDescriptor.getFields().iterator();
1970        while(it.hasNext()) {
1971            DatabaseField field = (DatabaseField)it.next();
1972            if(rootTable.equals(field.getTable())) {
1973                allFields.add(field);
1974            }
1975        }
1976        
1977        // statements will be executed in reverse order
1978

1979        SQLDeleteAllStatementForTempTable cleanupStatement = new SQLDeleteAllStatementForTempTable();
1980        cleanupStatement.setMode(SQLModifyAllStatementForTempTable.CLEANUP_TEMP_TABLE);
1981        cleanupStatement.setTable(rootTable);
1982        statements.addElement(cleanupStatement);
1983                        
1984        Iterator itTables = getDescriptor().getMultipleTableInsertOrder().iterator();
1985        while(itTables.hasNext()) {
1986            DatabaseTable table = (DatabaseTable)itTables.next();
1987            SQLDeleteAllStatementForTempTable deleteStatement = new SQLDeleteAllStatementForTempTable();
1988            deleteStatement.setMode(SQLModifyAllStatementForTempTable.UPDATE_ORIGINAL_TABLE);
1989            deleteStatement.setTable(rootTable);
1990            deleteStatement.setPrimaryKeyFields(rootTablePrimaryKeyFields);
1991            deleteStatement.setTargetTable(table);
1992            deleteStatement.setTargetPrimaryKeyFields(getPrimaryKeyFieldsForTable(table));
1993            statements.addElement(deleteStatement);
1994        }
1995        
1996        SQLSelectStatement selectStatement = createSQLSelectStatementForModifyAllForTempTable(null);
1997        SQLCall selectCall = (SQLCall)selectStatement.buildCall(getSession());
1998        SQLDeleteAllStatementForTempTable insertStatement = new SQLDeleteAllStatementForTempTable();
1999        insertStatement.setMode(SQLModifyAllStatementForTempTable.INSERT_INTO_TEMP_TABLE);
2000        insertStatement.setTable(rootTable);
2001        insertStatement.setTranslationRow(getTranslationRow());
2002        insertStatement.setSelectCall(selectCall);
2003        insertStatement.setPrimaryKeyFields(rootTablePrimaryKeyFields);
2004        statements.addElement(insertStatement);
2005        
2006        SQLDeleteAllStatementForTempTable createTempTableStatement = new SQLDeleteAllStatementForTempTable();
2007        createTempTableStatement.setMode(SQLModifyAllStatementForTempTable.CREATE_TEMP_TABLE);
2008        createTempTableStatement.setTable(rootTable);
2009        createTempTableStatement.setAllFields(allFields);
2010        createTempTableStatement.setPrimaryKeyFields(rootTablePrimaryKeyFields);
2011        statements.addElement(createTempTableStatement);
2012                
2013        return statements;
2014    }
2015
2016    protected Vector buildStatementsForUpdateAllForTempTables(DatabaseTable table, HashMap databaseFieldsToValues, Collection primaryKeyFields) {
2017        Vector statements = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(4);
2018        
2019        Vector allFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
2020        Iterator it = getDescriptor().getFields().iterator();
2021        while(it.hasNext()) {
2022            DatabaseField field = (DatabaseField)it.next();
2023            if(table.equals(field.getTable())) {
2024                allFields.add(field);
2025            }
2026        }
2027        
2028        SQLUpdateAllStatementForTempTable createTempTableStatement = new SQLUpdateAllStatementForTempTable();
2029        createTempTableStatement.setMode(SQLModifyAllStatementForTempTable.CREATE_TEMP_TABLE);
2030        createTempTableStatement.setTable(table);
2031        createTempTableStatement.setAllFields(allFields);
2032        createTempTableStatement.setAssignedFields(databaseFieldsToValues.keySet());
2033        createTempTableStatement.setPrimaryKeyFields(primaryKeyFields);
2034        statements.addElement(createTempTableStatement);
2035                
2036        SQLSelectStatement selectStatement = createSQLSelectStatementForModifyAllForTempTable(databaseFieldsToValues);
2037        SQLCall selectCall = (SQLCall)selectStatement.buildCall(getSession());
2038        SQLUpdateAllStatementForTempTable insertStatement = new SQLUpdateAllStatementForTempTable();
2039        insertStatement.setMode(SQLModifyAllStatementForTempTable.INSERT_INTO_TEMP_TABLE);
2040        insertStatement.setTable(table);
2041        insertStatement.setTranslationRow(getTranslationRow());
2042        insertStatement.setSelectCall(selectCall);
2043        insertStatement.setAssignedFields(databaseFieldsToValues.keySet());
2044        insertStatement.setPrimaryKeyFields(primaryKeyFields);
2045        statements.addElement(insertStatement);
2046        
2047        SQLUpdateAllStatementForTempTable updateStatement = new SQLUpdateAllStatementForTempTable();
2048        updateStatement.setMode(SQLModifyAllStatementForTempTable.UPDATE_ORIGINAL_TABLE);
2049        updateStatement.setTable(table);
2050        updateStatement.setTranslationRow(getTranslationRow());
2051        updateStatement.setAssignedFields(databaseFieldsToValues.keySet());
2052        updateStatement.setPrimaryKeyFields(primaryKeyFields);
2053        statements.addElement(updateStatement);
2054        
2055        SQLUpdateAllStatementForTempTable cleanupStatement = new SQLUpdateAllStatementForTempTable();
2056        cleanupStatement.setMode(SQLModifyAllStatementForTempTable.CLEANUP_TEMP_TABLE);
2057        cleanupStatement.setTable(table);
2058        statements.addElement(cleanupStatement);
2059                
2060        return statements;
2061    }
2062
2063    protected Collection getPrimaryKeyFieldsForTable(DatabaseTable table) {
2064        Collection primaryKeyFields;
2065        if(table.equals(getDescriptor().getTables().firstElement())) {
2066            primaryKeyFields = getDescriptor().getPrimaryKeyFields();
2067        } else {
2068            primaryKeyFields = ((Map)getDescriptor().getAdditionalTablePrimaryKeyFields().get(table)).values();
2069        }
2070        return primaryKeyFields;
2071    }
2072    
2073    /**
2074     * INTERNAL
2075     * Read all rows from the database. The code to retrieve the full inheritance hierarchy was removed.
2076     *
2077     * @return Vector containing the database rows.
2078     * @exception DatabaseException - an error has occurred on the database.
2079     */

2080    public Vector selectAllReportQueryRows() throws DatabaseException {
2081        return selectAllRowsFromTable();
2082    }
2083
2084    /**
2085     * Read all rows from the database.
2086     * @return Vector containing the database rows.
2087     * @exception DatabaseException - an error has occurred on the database.
2088     */

2089    public Vector selectAllRows() throws DatabaseException {
2090        if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().requiresMultipleTableSubclassRead() && (!getDescriptor().getInheritancePolicy().hasView())) {
2091            return getDescriptor().getInheritancePolicy().selectAllRowUsingMultipleTableSubclassRead((ReadAllQuery)getQuery());
2092        } else {
2093            return selectAllRowsFromTable();
2094        }
2095    }
2096
2097    /**
2098     * Read all rows from the database.
2099     * This is used only from query mechanism on a abstract-multiple table read.
2100     */

2101    public Vector selectAllRowsFromConcreteTable() throws DatabaseException {
2102        setSQLStatement(buildConcreteSelectStatement());
2103        // Must also build the call as mt reads are not pre-built.
2104
super.prepareSelectAllRows();
2105
2106        return super.selectAllRows();
2107    }
2108
2109    /**
2110     * Read all rows from the database.
2111     * @return Vector containing the database rows.
2112     * @exception DatabaseException - an error has occurred on the database.
2113     */

2114    public Vector selectAllRowsFromTable() throws DatabaseException {
2115        return super.selectAllRows();
2116    }
2117
2118    /**
2119     * Read a single row from the database. Create an SQL statement object,
2120     * use it to create an SQL command string, and delegate row building
2121     * responsibility to the accessor.
2122     */

2123    public AbstractRecord selectOneRow() throws DatabaseException {
2124        if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().requiresMultipleTableSubclassRead() && (!getDescriptor().getInheritancePolicy().hasView())) {
2125            return getDescriptor().getInheritancePolicy().selectOneRowUsingMultipleTableSubclassRead((ReadObjectQuery)getQuery());
2126        } else {
2127            return selectOneRowFromTable();
2128        }
2129    }
2130
2131    /**
2132     * Read a single row from the database.
2133     * This is used from query mechanism during an abstract-multiple table read.
2134     */

2135    public AbstractRecord selectOneRowFromConcreteTable() throws DatabaseException {
2136        setSQLStatement(buildConcreteSelectStatement());
2137        // Must also build the call as mt reads are not pre-built.
2138
super.prepareSelectOneRow();
2139
2140        return super.selectOneRow();
2141    }
2142
2143    /**
2144     * Read a single row from the database. Create an SQL statement object,
2145     * use it to create an SQL command string, and delegate row building
2146     * responsibility to the accessor.
2147     * @param fields - fields used to build database row
2148     * @return row containing data
2149     * @exception DatabaseException - an error has occurred on the database
2150     */

2151    public AbstractRecord selectOneRowFromTable() throws DatabaseException {
2152        return super.selectOneRow();
2153    }
2154
2155    /**
2156     * Set the selection criteria of the query.
2157     */

2158    public void setSelectionCriteria(Expression expression) {
2159        this.selectionCriteria = expression;
2160    }
2161}
2162
Popular Tags