KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > access > trans > SelectTranslator


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne.access.trans;
57
58 import java.sql.Types JavaDoc;
59 import java.util.ArrayList JavaDoc;
60 import java.util.Collection JavaDoc;
61 import java.util.Collections JavaDoc;
62 import java.util.HashMap JavaDoc;
63 import java.util.HashSet JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.List JavaDoc;
66 import java.util.Map JavaDoc;
67 import java.util.Set JavaDoc;
68
69 import org.objectstyle.cayenne.CayenneRuntimeException;
70 import org.objectstyle.cayenne.access.jdbc.ColumnDescriptor;
71 import org.objectstyle.cayenne.exp.Expression;
72 import org.objectstyle.cayenne.map.DbAttribute;
73 import org.objectstyle.cayenne.map.DbEntity;
74 import org.objectstyle.cayenne.map.DbJoin;
75 import org.objectstyle.cayenne.map.DbRelationship;
76 import org.objectstyle.cayenne.map.DerivedDbEntity;
77 import org.objectstyle.cayenne.map.EntityInheritanceTree;
78 import org.objectstyle.cayenne.map.ObjAttribute;
79 import org.objectstyle.cayenne.map.ObjEntity;
80 import org.objectstyle.cayenne.map.ObjRelationship;
81 import org.objectstyle.cayenne.query.PrefetchSelectQuery;
82 import org.objectstyle.cayenne.query.SelectQuery;
83
84 /**
85  * A builder of JDBC PreparedStatements based on Cayenne SelectQueries. Translates
86  * SelectQuery to parameterized SQL string and wraps it in a PreparedStatement.
87  * SelectTranslator is stateful and thread-unsafe.
88  *
89  * @author Andrei Adamchik
90  */

91 public class SelectTranslator extends QueryAssembler {
92
93     protected static final int[] UNSUPPORTED_DISTINCT_TYPES = new int[] {
94             Types.BLOB, Types.CLOB, Types.LONGVARBINARY, Types.LONGVARCHAR
95     };
96
97     protected static boolean isUnsupportedForDistinct(int type) {
98         for (int i = 0; i < UNSUPPORTED_DISTINCT_TYPES.length; i++) {
99             if (UNSUPPORTED_DISTINCT_TYPES[i] == type) {
100                 return true;
101             }
102         }
103
104         return false;
105     }
106
107     final Map JavaDoc aliasLookup = new HashMap JavaDoc();
108
109     final List JavaDoc tableList = new ArrayList JavaDoc();
110     final List JavaDoc aliasList = new ArrayList JavaDoc();
111     final List JavaDoc dbRelList = new ArrayList JavaDoc();
112
113     List JavaDoc resultColumns;
114     List JavaDoc groupByList;
115
116     int aliasCounter;
117
118     boolean suppressingDistinct;
119
120     /**
121      * If set to <code>true</code>, indicates that distinct select query is required no
122      * matter what the original query settings where. This flag can be set when joins are
123      * created using "to-many" relationships.
124      */

125     boolean forcingDistinct;
126
127     /**
128      * Returns a list of DbAttributes representing columns in this query.
129      *
130      * @deprecated since 1.2 - contents of this list are now ColumnDescriptors, not
131      * DbAttributes. Anyway, use getResultColumns() instead to reduce
132      * confusion.
133      */

134     protected List JavaDoc getColumns() {
135         return resultColumns;
136     }
137
138     /**
139      * Returns query translated to SQL. This is a main work method of the
140      * SelectTranslator.
141      */

142     public String JavaDoc createSqlString() throws Exception JavaDoc {
143         forcingDistinct = false;
144
145         // build column list
146
this.resultColumns = buildResultColumns();
147
148         QualifierTranslator tr = adapter.getQualifierTranslator(this);
149
150         // build parent qualifier
151
// Parent qualifier translation must PRECEED main qualifier
152
// since it will be appended first and its parameters must
153
// go first as well
154
String JavaDoc parentQualifierStr = null;
155         if (getSelectQuery().isQualifiedOnParent()) {
156             tr.setTranslateParentQual(true);
157             parentQualifierStr = tr.doTranslation();
158         }
159
160         // build main qualifier
161
tr.setTranslateParentQual(false);
162         String JavaDoc qualifierStr = tr.doTranslation();
163
164         // build GROUP BY
165
this.groupByList = buildGroupByList();
166
167         // build ORDER BY
168
OrderingTranslator orderingTranslator = new OrderingTranslator(this);
169         String JavaDoc orderByStr = orderingTranslator.doTranslation();
170
171         // assemble
172
StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
173         queryBuf.append("SELECT ");
174
175         // check if DISTINCT is appropriate
176
// side effect: "suppressingDistinct" flag may end up being flipped here
177
if (forcingDistinct || getSelectQuery().isDistinct()) {
178
179             suppressingDistinct = false;
180             Iterator JavaDoc it = resultColumns.iterator();
181             while (it.hasNext()) {
182                 ColumnDescriptor column = (ColumnDescriptor) it.next();
183                 if (isUnsupportedForDistinct(column.getJdbcType())) {
184                     suppressingDistinct = true;
185                     break;
186                 }
187             }
188
189             if (!suppressingDistinct) {
190                 queryBuf.append("DISTINCT ");
191             }
192         }
193
194         // convert ColumnDescriptors to column names
195
List JavaDoc selectColumnExpList = new ArrayList JavaDoc();
196
197         Iterator JavaDoc it = resultColumns.iterator();
198         while (it.hasNext()) {
199             ColumnDescriptor column = (ColumnDescriptor) it.next();
200             selectColumnExpList.add(column.getQualifiedColumnName());
201         }
202
203         // append any column expressions used in the order by if this query
204
// uses the DISTINCT modifier
205
if (forcingDistinct || getSelectQuery().isDistinct()) {
206             List JavaDoc orderByColumnList = orderingTranslator.getOrderByColumnList();
207             for (int i = 0; i < orderByColumnList.size(); i++) {
208                 // Convert to ColumnDescriptors??
209
Object JavaDoc orderByColumnExp = orderByColumnList.get(i);
210                 if (!selectColumnExpList.contains(orderByColumnExp)) {
211                     selectColumnExpList.add(orderByColumnExp);
212                 }
213             }
214         }
215
216         // append columns (unroll the loop's first element)
217
int columnCount = selectColumnExpList.size();
218         queryBuf.append((String JavaDoc) selectColumnExpList.get(0));
219         // assume there is at least 1 element
220
for (int i = 1; i < columnCount; i++) {
221             queryBuf.append(", ");
222             queryBuf.append((String JavaDoc) selectColumnExpList.get(i));
223         }
224
225         // append from clause
226
queryBuf.append(" FROM ");
227
228         // append table list (unroll loop's 1st element)
229
int tableCount = tableList.size();
230         appendTable(queryBuf, 0); // assume there is at least 1 table
231
for (int i = 1; i < tableCount; i++) {
232             queryBuf.append(", ");
233             appendTable(queryBuf, i);
234         }
235
236         // append db relationship joins if any
237
boolean hasWhere = false;
238         int dbRelCount = dbRelList.size();
239         if (dbRelCount > 0) {
240             hasWhere = true;
241             queryBuf.append(" WHERE ");
242
243             appendJoins(queryBuf, 0);
244             for (int i = 1; i < dbRelCount; i++) {
245                 queryBuf.append(" AND ");
246                 appendJoins(queryBuf, i);
247             }
248         }
249
250         // append parent qualifier if any
251
if (parentQualifierStr != null) {
252             if (hasWhere) {
253                 queryBuf.append(" AND (");
254                 queryBuf.append(parentQualifierStr);
255                 queryBuf.append(")");
256             }
257             else {
258                 hasWhere = true;
259                 queryBuf.append(" WHERE ");
260                 queryBuf.append(parentQualifierStr);
261             }
262         }
263
264         // append group by
265
boolean hasGroupBy = false;
266         if (groupByList != null) {
267             int groupByCount = groupByList.size();
268             if (groupByCount > 0) {
269                 hasGroupBy = true;
270                 queryBuf.append(" GROUP BY ");
271                 appendGroupBy(queryBuf, 0);
272                 for (int i = 1; i < groupByCount; i++) {
273                     queryBuf.append(", ");
274                     appendGroupBy(queryBuf, i);
275                 }
276             }
277         }
278
279         // append qualifier
280
if (qualifierStr != null) {
281             if (hasGroupBy) {
282                 queryBuf.append(" HAVING ");
283                 queryBuf.append(qualifierStr);
284             }
285             else {
286                 if (hasWhere) {
287                     queryBuf.append(" AND (");
288                     queryBuf.append(qualifierStr);
289                     queryBuf.append(")");
290                 }
291                 else {
292                     hasWhere = true;
293                     queryBuf.append(" WHERE ");
294                     queryBuf.append(qualifierStr);
295                 }
296             }
297         }
298
299         // append prebuilt ordering
300
if (orderByStr != null) {
301             queryBuf.append(" ORDER BY ").append(orderByStr);
302         }
303
304         return queryBuf.toString();
305     }
306
307     /**
308      * Returns a list of ColumnDescriptors for the query columns.
309      *
310      * @since 1.2
311      */

312     public ColumnDescriptor[] getResultColumns() {
313         if (resultColumns == null || resultColumns.isEmpty()) {
314             return new ColumnDescriptor[0];
315         }
316
317         return (ColumnDescriptor[]) resultColumns
318                 .toArray(new ColumnDescriptor[resultColumns.size()]);
319     }
320
321     /**
322      * Returns true if SelectTranslator determined that a query requiring DISTINCT can't
323      * be run with DISTINCT keyword for internal reasons. If this method returns true,
324      * DataNode may need to do in-memory distinct filtering.
325      *
326      * @since 1.1
327      */

328     public boolean isSuppressingDistinct() {
329         return suppressingDistinct;
330     }
331
332     private SelectQuery getSelectQuery() {
333         return (SelectQuery) getQuery();
334     }
335
336     /**
337      * Creates a list of columns used in the query's GROUP BY clause.
338      */

339     private List JavaDoc buildGroupByList() {
340         DbEntity dbEntity = getRootDbEntity();
341         return (dbEntity instanceof DerivedDbEntity) ? ((DerivedDbEntity) dbEntity)
342                 .getGroupByAttributes() : Collections.EMPTY_LIST;
343     }
344
345     List JavaDoc buildResultColumns() {
346
347         // create alias for root table
348
newAliasForTable(getRootDbEntity());
349
350         List JavaDoc columns = new ArrayList JavaDoc();
351         SelectQuery query = getSelectQuery();
352
353         // for query with custom attributes use a different strategy
354
if (query.isFetchingCustomAttributes()) {
355             appendCustomColumns(columns, query);
356         }
357         else {
358             appendQueryColumns(columns, query);
359         }
360
361         return columns;
362     }
363
364     /**
365      * Appends columns needed for object SelectQuery to the provided columns list.
366      */

367     // TODO: this whole method screams REFACTORING!!!
368
List JavaDoc appendQueryColumns(List JavaDoc columns, SelectQuery query) {
369
370         Set JavaDoc attributes = new HashSet JavaDoc();
371
372         // fetched attributes include attributes that are either:
373
//
374
// * class properties
375
// * PK
376
// * FK used in relationships
377
// * GROUP BY
378
// * joined prefetch PK
379

380         ObjEntity oe = getRootEntity();
381
382         // null tree will indicate that we don't take inheritance into account
383
EntityInheritanceTree tree = null;
384
385         if (query.isResolvingInherited()) {
386             tree = getRootInheritanceTree();
387         }
388
389         // ObjEntity attrs
390
Iterator JavaDoc attrs = (tree != null) ? tree.allAttributes().iterator() : oe
391                 .getAttributes()
392                 .iterator();
393         while (attrs.hasNext()) {
394             ObjAttribute oa = (ObjAttribute) attrs.next();
395             Iterator JavaDoc dbPathIterator = oa.getDbPathIterator();
396             while (dbPathIterator.hasNext()) {
397                 Object JavaDoc pathPart = dbPathIterator.next();
398                 if (pathPart instanceof DbRelationship) {
399                     DbRelationship rel = (DbRelationship) pathPart;
400                     dbRelationshipAdded(rel);
401                 }
402                 else if (pathPart instanceof DbAttribute) {
403                     DbAttribute dbAttr = (DbAttribute) pathPart;
404                     if (dbAttr == null) {
405                         throw new CayenneRuntimeException(
406                                 "ObjAttribute has no DbAttribute: " + oa.getName());
407                     }
408
409                     appendColumn(columns, oa, dbAttr, attributes, null);
410                 }
411             }
412         }
413
414         // relationship keys
415
Iterator JavaDoc rels = (tree != null) ? tree.allRelationships().iterator() : oe
416                 .getRelationships()
417                 .iterator();
418         while (rels.hasNext()) {
419             ObjRelationship rel = (ObjRelationship) rels.next();
420             DbRelationship dbRel = (DbRelationship) rel.getDbRelationships().get(0);
421
422             List JavaDoc joins = dbRel.getJoins();
423             int len = joins.size();
424             for (int i = 0; i < len; i++) {
425                 DbJoin join = (DbJoin) joins.get(i);
426                 DbAttribute src = join.getSource();
427                 appendColumn(columns, null, src, attributes, null);
428             }
429         }
430
431         // add remaining needed attrs from DbEntity
432

433         DbEntity table = getRootDbEntity();
434         Iterator JavaDoc pk = table.getPrimaryKey().iterator();
435         while (pk.hasNext()) {
436             DbAttribute dba = (DbAttribute) pk.next();
437             appendColumn(columns, null, dba, attributes, null);
438         }
439
440         // add FKs for Prefetch selects for to-many ObjRelationships with no reverse
441
if (query instanceof PrefetchSelectQuery) {
442             PrefetchSelectQuery pq = (PrefetchSelectQuery) query;
443             ObjRelationship r = pq.getLastPrefetchHint();
444             if ((r != null) && (r.getReverseRelationship() == null)) {
445
446                 // Prefetching a single step toMany relationship which
447
// has no reverse obj relationship. Add the FK attributes
448
// of the relationship (wouldn't otherwise be included)
449

450                 // TODO: seems like a hack for srcPkSnapshotWithTargetSnapshot benefit;
451
// if we have a flat row with multiple joins, this will violate the naming
452
// conventions.
453
DbRelationship dbRel = (DbRelationship) r.getDbRelationships().get(0);
454
455                 List JavaDoc joins = dbRel.getJoins();
456                 for (int j = 0; j < joins.size(); j++) {
457                     DbJoin join = (DbJoin) joins.get(j);
458                     DbAttribute target = join.getTarget();
459                     appendColumn(columns, null, target, attributes, null);
460                 }
461             }
462         }
463
464         // handle joint prefetches
465
if (!query.getJointPrefetches().isEmpty()) {
466             Iterator JavaDoc jointPrefetches = query.getJointPrefetches().iterator();
467             while (jointPrefetches.hasNext()) {
468                 String JavaDoc prefetch = (String JavaDoc) jointPrefetches.next();
469
470                 // for each prefetch add all joins plus columns from the target entity
471
Expression prefetchExp = Expression.fromString(prefetch);
472                 Expression dbPrefetch = oe.translateToDbPath(prefetchExp);
473
474                 // find target entity
475
Iterator JavaDoc it = table.resolvePathComponents(dbPrefetch);
476
477                 DbRelationship r = null;
478                 while (it.hasNext()) {
479                     r = (DbRelationship) it.next();
480                     dbRelationshipAdded(r);
481                 }
482
483                 if (r == null) {
484                     throw new CayenneRuntimeException("Invalid joint prefetch '"
485                             + prefetch
486                             + "' for entity: "
487                             + oe.getName());
488                 }
489
490                 // add columns from the target entity, skipping those that are an FK to
491
// source entity
492

493                 Collection JavaDoc skipColumns = Collections.EMPTY_LIST;
494                 if (r.getSourceEntity() == table) {
495                     skipColumns = new ArrayList JavaDoc(2);
496                     Iterator JavaDoc joins = r.getJoins().iterator();
497                     while (joins.hasNext()) {
498                         DbJoin join = (DbJoin) joins.next();
499                         if (attributes.contains(join.getSource())) {
500                             skipColumns.add(join.getTarget());
501                         }
502                     }
503                 }
504
505                 // go via target OE to make sure that Java types are mapped correctly...
506
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
507                 Iterator JavaDoc targetObjAttrs = targetRel
508                         .getTargetEntity()
509                         .getAttributes()
510                         .iterator();
511                 while (targetObjAttrs.hasNext()) {
512                     ObjAttribute oa = (ObjAttribute) targetObjAttrs.next();
513                     Iterator JavaDoc dbPathIterator = oa.getDbPathIterator();
514                     while (dbPathIterator.hasNext()) {
515                         Object JavaDoc pathPart = dbPathIterator.next();
516                         if (pathPart instanceof DbRelationship) {
517                             DbRelationship rel = (DbRelationship) pathPart;
518                             dbRelationshipAdded(rel);
519                         }
520                         else if (pathPart instanceof DbAttribute) {
521                             DbAttribute attribute = (DbAttribute) pathPart;
522                             if (attribute == null) {
523                                 throw new CayenneRuntimeException(
524                                         "ObjAttribute has no DbAttribute: "
525                                                 + oa.getName());
526                             }
527
528                             if (!skipColumns.contains(attribute)) {
529                                 appendColumn(columns,
530                                         oa,
531                                         attribute,
532                                         attributes,
533                                         dbPrefetch);
534                             }
535                         }
536                     }
537                 }
538
539                 // append remaining target attributes such as keys
540
Iterator JavaDoc targetAttributes = r
541                         .getTargetEntity()
542                         .getAttributes()
543                         .iterator();
544                 while (targetAttributes.hasNext()) {
545                     DbAttribute attribute = (DbAttribute) targetAttributes.next();
546                     if (!skipColumns.contains(attribute)) {
547                         appendColumn(columns, null, attribute, attributes, dbPrefetch);
548                     }
549                 }
550             }
551         }
552
553         return columns;
554     }
555
556     /**
557      * Appends custom columns from SelectQuery to the provided list.
558      */

559     List JavaDoc appendCustomColumns(List JavaDoc columns, SelectQuery query) {
560
561         List JavaDoc customAttributes = query.getCustomDbAttributes();
562         DbEntity table = getRootDbEntity();
563         int len = customAttributes.size();
564
565         for (int i = 0; i < len; i++) {
566             DbAttribute attribute = (DbAttribute) table
567                     .getAttribute((String JavaDoc) customAttributes.get(i));
568             if (attribute == null) {
569                 throw new CayenneRuntimeException("Attribute does not exist: "
570                         + customAttributes.get(i));
571             }
572
573             String JavaDoc alias = aliasForTable((DbEntity) attribute.getEntity());
574             columns.add(new ColumnDescriptor(attribute, alias));
575         }
576
577         return columns;
578     }
579
580     private void appendColumn(
581             List JavaDoc columns,
582             ObjAttribute objAttribute,
583             DbAttribute attribute,
584             Set JavaDoc skipSet,
585             Expression dbPath) {
586
587         if (skipSet.add(attribute)) {
588             String JavaDoc alias = aliasForTable((DbEntity) attribute.getEntity());
589             ColumnDescriptor column = (objAttribute != null) ? new ColumnDescriptor(
590                     objAttribute,
591                     attribute,
592                     alias) : new ColumnDescriptor(attribute, alias);
593
594             // used for joint prefetches
595
if (dbPath != null) {
596                 String JavaDoc path = dbPath.toString().substring("db:".length());
597                 column.setLabel(path + '.' + attribute.getName());
598             }
599
600             columns.add(column);
601         }
602     }
603
604     private void appendGroupBy(StringBuffer JavaDoc queryBuf, int index) {
605         DbAttribute column = (DbAttribute) groupByList.get(index);
606         String JavaDoc alias = aliasForTable((DbEntity) column.getEntity());
607         queryBuf.append(column.getAliasedName(alias));
608     }
609
610     private void appendTable(StringBuffer JavaDoc queryBuf, int index) {
611         DbEntity ent = (DbEntity) tableList.get(index);
612         queryBuf.append(ent.getFullyQualifiedName());
613         //The alias should be the alias from the same index in aliasList, not that
614
// returned by aliasForTable.
615
queryBuf.append(' ').append((String JavaDoc) aliasList.get(index));
616     }
617
618     private void appendJoins(StringBuffer JavaDoc queryBuf, int index) {
619         DbRelationship rel = (DbRelationship) dbRelList.get(index);
620         String JavaDoc srcAlias = aliasForTable((DbEntity) rel.getSourceEntity());
621         String JavaDoc targetAlias = (String JavaDoc) aliasLookup.get(rel);
622
623         boolean andFlag = false;
624
625         List JavaDoc joins = rel.getJoins();
626         int len = joins.size();
627         for (int i = 0; i < len; i++) {
628             DbJoin join = (DbJoin) joins.get(i);
629
630             if (andFlag) {
631                 queryBuf.append(" AND ");
632             }
633             else {
634                 andFlag = true;
635             }
636
637             queryBuf
638                     .append(srcAlias)
639                     .append('.')
640                     .append(join.getSourceName())
641                     .append(" = ")
642                     .append(targetAlias)
643                     .append('.')
644                     .append(join.getTargetName());
645         }
646     }
647
648     /**
649      * Stores a new relationship in an internal list. Later it will be used to create
650      * joins to relationship destination table.
651      */

652     public void dbRelationshipAdded(DbRelationship rel) {
653         if (rel.isToMany()) {
654             forcingDistinct = true;
655         }
656
657         String JavaDoc existAlias = (String JavaDoc) aliasLookup.get(rel);
658
659         if (existAlias == null) {
660             dbRelList.add(rel);
661
662             // add alias for the destination table of the relationship
663
String JavaDoc newAlias = newAliasForTable((DbEntity) rel.getTargetEntity());
664             aliasLookup.put(rel, newAlias);
665         }
666     }
667
668     /**
669      * Sets up and returns a new alias for a speciafied table.
670      */

671     protected String JavaDoc newAliasForTable(DbEntity ent) {
672         if (ent instanceof DerivedDbEntity) {
673             ent = ((DerivedDbEntity) ent).getParentEntity();
674         }
675
676         String JavaDoc newAlias = "t" + aliasCounter++;
677         tableList.add(ent);
678         aliasList.add(newAlias);
679         return newAlias;
680     }
681
682     public String JavaDoc aliasForTable(DbEntity ent, DbRelationship rel) {
683         return (String JavaDoc) aliasLookup.get(rel);
684     }
685
686     /**
687      * Overrides superclass implementation. Will return an alias that should be used for a
688      * specified DbEntity in the query (or null if this DbEntity is not included in the
689      * FROM clause).
690      */

691     public String JavaDoc aliasForTable(DbEntity ent) {
692         if (ent instanceof DerivedDbEntity) {
693             ent = ((DerivedDbEntity) ent).getParentEntity();
694         }
695
696         int entIndex = tableList.indexOf(ent);
697         if (entIndex >= 0) {
698             return (String JavaDoc) aliasList.get(entIndex);
699         }
700         else {
701             StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
702             msg.append("Alias not found, DbEntity: '").append(ent != null
703                     ? ent.getName()
704                     : "<null entity>").append("'\nExisting aliases:");
705
706             int len = aliasList.size();
707             for (int i = 0; i < len; i++) {
708                 String JavaDoc dbeName = (tableList.get(i) != null) ? ((DbEntity) tableList
709                         .get(i)).getName() : "<null entity>";
710                 msg.append("\n").append(aliasList.get(i)).append(" => ").append(dbeName);
711             }
712
713             throw new CayenneRuntimeException(msg.toString());
714         }
715     }
716
717     /**
718      * Always returns true.
719      */

720     public boolean supportsTableAliases() {
721         return true;
722     }
723 }
Popular Tags