KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.access.trans;
21
22 import java.sql.Types JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32
33 import org.apache.cayenne.CayenneRuntimeException;
34 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
35 import org.apache.cayenne.exp.Expression;
36 import org.apache.cayenne.map.DbAttribute;
37 import org.apache.cayenne.map.DbEntity;
38 import org.apache.cayenne.map.DbJoin;
39 import org.apache.cayenne.map.DbRelationship;
40 import org.apache.cayenne.map.DerivedDbEntity;
41 import org.apache.cayenne.map.ObjAttribute;
42 import org.apache.cayenne.map.ObjEntity;
43 import org.apache.cayenne.map.ObjRelationship;
44 import org.apache.cayenne.query.PrefetchSelectQuery;
45 import org.apache.cayenne.query.PrefetchTreeNode;
46 import org.apache.cayenne.query.SelectQuery;
47 import org.apache.cayenne.reflect.ArcProperty;
48 import org.apache.cayenne.reflect.AttributeProperty;
49 import org.apache.cayenne.reflect.ClassDescriptor;
50 import org.apache.cayenne.reflect.PropertyVisitor;
51 import org.apache.cayenne.reflect.ToManyProperty;
52 import org.apache.cayenne.reflect.ToOneProperty;
53
54 /**
55  * A builder of JDBC PreparedStatements based on Cayenne SelectQueries. Translates
56  * SelectQuery to parameterized SQL string and wraps it in a PreparedStatement.
57  * SelectTranslator is stateful and thread-unsafe.
58  *
59  * @author Andrus Adamchik
60  */

61 public class SelectTranslator extends QueryAssembler {
62
63     protected static final int[] UNSUPPORTED_DISTINCT_TYPES = new int[] {
64             Types.BLOB, Types.CLOB, Types.LONGVARBINARY, Types.LONGVARCHAR
65     };
66
67     protected static boolean isUnsupportedForDistinct(int type) {
68         for (int i = 0; i < UNSUPPORTED_DISTINCT_TYPES.length; i++) {
69             if (UNSUPPORTED_DISTINCT_TYPES[i] == type) {
70                 return true;
71             }
72         }
73
74         return false;
75     }
76
77     final Map JavaDoc aliasLookup = new HashMap JavaDoc();
78
79     final List JavaDoc tableList = new ArrayList JavaDoc();
80     final List JavaDoc aliasList = new ArrayList JavaDoc();
81     final List JavaDoc dbRelList = new ArrayList JavaDoc();
82
83     List JavaDoc resultColumns;
84     List JavaDoc groupByList;
85     Map JavaDoc attributeOverrides;
86     Map JavaDoc defaultAttributesByColumn;
87
88     int aliasCounter;
89
90     boolean suppressingDistinct;
91
92     /**
93      * If set to <code>true</code>, indicates that distinct select query is required no
94      * matter what the original query settings where. This flag can be set when joins are
95      * created using "to-many" relationships.
96      */

97     boolean forcingDistinct;
98
99     /**
100      * Returns query translated to SQL. This is a main work method of the
101      * SelectTranslator.
102      */

103     public String JavaDoc createSqlString() throws Exception JavaDoc {
104         forcingDistinct = false;
105
106         // build column list
107
this.resultColumns = buildResultColumns();
108
109         QualifierTranslator tr = adapter.getQualifierTranslator(this);
110
111         // build parent qualifier
112
// Parent qualifier translation must PRECEED main qualifier
113
// since it will be appended first and its parameters must
114
// go first as well
115
String JavaDoc parentQualifierStr = null;
116         if (getSelectQuery().isQualifiedOnParent()) {
117             tr.setTranslateParentQual(true);
118             parentQualifierStr = tr.doTranslation();
119         }
120
121         // build main qualifier
122
tr.setTranslateParentQual(false);
123         String JavaDoc qualifierStr = tr.doTranslation();
124
125         // build GROUP BY
126
this.groupByList = buildGroupByList();
127
128         // build ORDER BY
129
OrderingTranslator orderingTranslator = new OrderingTranslator(this);
130         String JavaDoc orderByStr = orderingTranslator.doTranslation();
131
132         // assemble
133
StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc();
134         queryBuf.append("SELECT ");
135
136         // check if DISTINCT is appropriate
137
// side effect: "suppressingDistinct" flag may end up being flipped here
138
if (forcingDistinct || getSelectQuery().isDistinct()) {
139
140             suppressingDistinct = false;
141             Iterator JavaDoc it = resultColumns.iterator();
142             while (it.hasNext()) {
143                 ColumnDescriptor column = (ColumnDescriptor) it.next();
144                 if (isUnsupportedForDistinct(column.getJdbcType())) {
145                     suppressingDistinct = true;
146                     break;
147                 }
148             }
149
150             if (!suppressingDistinct) {
151                 queryBuf.append("DISTINCT ");
152             }
153         }
154
155         // convert ColumnDescriptors to column names
156
List JavaDoc selectColumnExpList = new ArrayList JavaDoc();
157
158         Iterator JavaDoc it = resultColumns.iterator();
159         while (it.hasNext()) {
160             ColumnDescriptor column = (ColumnDescriptor) it.next();
161             selectColumnExpList.add(column.getQualifiedColumnName());
162         }
163
164         // append any column expressions used in the order by if this query
165
// uses the DISTINCT modifier
166
if (forcingDistinct || getSelectQuery().isDistinct()) {
167             List JavaDoc orderByColumnList = orderingTranslator.getOrderByColumnList();
168             for (int i = 0; i < orderByColumnList.size(); i++) {
169                 // Convert to ColumnDescriptors??
170
Object JavaDoc orderByColumnExp = orderByColumnList.get(i);
171                 if (!selectColumnExpList.contains(orderByColumnExp)) {
172                     selectColumnExpList.add(orderByColumnExp);
173                 }
174             }
175         }
176
177         // append columns (unroll the loop's first element)
178
int columnCount = selectColumnExpList.size();
179         queryBuf.append((String JavaDoc) selectColumnExpList.get(0));
180         // assume there is at least 1 element
181
for (int i = 1; i < columnCount; i++) {
182             queryBuf.append(", ");
183             queryBuf.append((String JavaDoc) selectColumnExpList.get(i));
184         }
185
186         // append from clause
187
queryBuf.append(" FROM ");
188
189         // append table list (unroll loop's 1st element)
190
int tableCount = tableList.size();
191         appendTable(queryBuf, 0); // assume there is at least 1 table
192
for (int i = 1; i < tableCount; i++) {
193             queryBuf.append(", ");
194             appendTable(queryBuf, i);
195         }
196
197         // append db relationship joins if any
198
boolean hasWhere = false;
199         int dbRelCount = dbRelList.size();
200         if (dbRelCount > 0) {
201             hasWhere = true;
202             queryBuf.append(" WHERE ");
203
204             appendJoins(queryBuf, 0);
205             for (int i = 1; i < dbRelCount; i++) {
206                 queryBuf.append(" AND ");
207                 appendJoins(queryBuf, i);
208             }
209         }
210
211         // append parent qualifier if any
212
if (parentQualifierStr != null) {
213             if (hasWhere) {
214                 queryBuf.append(" AND (");
215                 queryBuf.append(parentQualifierStr);
216                 queryBuf.append(")");
217             }
218             else {
219                 hasWhere = true;
220                 queryBuf.append(" WHERE ");
221                 queryBuf.append(parentQualifierStr);
222             }
223         }
224
225         // append group by
226
boolean hasGroupBy = false;
227         if (groupByList != null) {
228             int groupByCount = groupByList.size();
229             if (groupByCount > 0) {
230                 hasGroupBy = true;
231                 queryBuf.append(" GROUP BY ");
232                 appendGroupBy(queryBuf, 0);
233                 for (int i = 1; i < groupByCount; i++) {
234                     queryBuf.append(", ");
235                     appendGroupBy(queryBuf, i);
236                 }
237             }
238         }
239
240         // append qualifier
241
if (qualifierStr != null) {
242             if (hasGroupBy) {
243                 queryBuf.append(" HAVING ");
244                 queryBuf.append(qualifierStr);
245             }
246             else {
247                 if (hasWhere) {
248                     queryBuf.append(" AND (");
249                     queryBuf.append(qualifierStr);
250                     queryBuf.append(")");
251                 }
252                 else {
253                     hasWhere = true;
254                     queryBuf.append(" WHERE ");
255                     queryBuf.append(qualifierStr);
256                 }
257             }
258         }
259
260         // append prebuilt ordering
261
if (orderByStr != null) {
262             queryBuf.append(" ORDER BY ").append(orderByStr);
263         }
264
265         return queryBuf.toString();
266     }
267
268     /**
269      * Returns a list of ColumnDescriptors for the query columns.
270      *
271      * @since 1.2
272      */

273     public ColumnDescriptor[] getResultColumns() {
274         if (resultColumns == null || resultColumns.isEmpty()) {
275             return new ColumnDescriptor[0];
276         }
277
278         return (ColumnDescriptor[]) resultColumns
279                 .toArray(new ColumnDescriptor[resultColumns.size()]);
280     }
281
282     /**
283      * Returns a map of ColumnDescriptors keyed by ObjAttribute for columns that may need
284      * to be reprocessed manually due to incompatible mappings along the inheritance
285      * hierarchy.
286      *
287      * @since 1.2
288      */

289     public Map JavaDoc getAttributeOverrides() {
290         return attributeOverrides != null ? attributeOverrides : Collections.EMPTY_MAP;
291     }
292
293     /**
294      * Returns true if SelectTranslator determined that a query requiring DISTINCT can't
295      * be run with DISTINCT keyword for internal reasons. If this method returns true,
296      * DataNode may need to do in-memory distinct filtering.
297      *
298      * @since 1.1
299      */

300     public boolean isSuppressingDistinct() {
301         return suppressingDistinct;
302     }
303
304     private SelectQuery getSelectQuery() {
305         return (SelectQuery) getQuery();
306     }
307
308     /**
309      * Creates a list of columns used in the query's GROUP BY clause.
310      */

311     private List JavaDoc buildGroupByList() {
312         DbEntity dbEntity = getRootDbEntity();
313         return (dbEntity instanceof DerivedDbEntity) ? ((DerivedDbEntity) dbEntity)
314                 .getGroupByAttributes() : Collections.EMPTY_LIST;
315     }
316
317     List JavaDoc buildResultColumns() {
318
319         this.defaultAttributesByColumn = new HashMap JavaDoc();
320
321         // create alias for root table
322
newAliasForTable(getRootDbEntity());
323
324         List JavaDoc columns = new ArrayList JavaDoc();
325         SelectQuery query = getSelectQuery();
326
327         // for query with custom attributes use a different strategy
328
if (query.isFetchingCustomAttributes()) {
329             appendCustomColumns(columns, query);
330         }
331         else {
332             appendQueryColumns(columns, query);
333         }
334
335         return columns;
336     }
337
338     /**
339      * Appends columns needed for object SelectQuery to the provided columns list.
340      */

341     // TODO: this whole method screams REFACTORING!!!
342
List JavaDoc appendQueryColumns(final List JavaDoc columns, SelectQuery query) {
343
344         final Set JavaDoc attributes = new HashSet JavaDoc();
345
346         // fetched attributes include attributes that are either:
347
//
348
// * class properties
349
// * PK
350
// * FK used in relationships
351
// * GROUP BY
352
// * joined prefetch PK
353

354         ClassDescriptor descriptor = query
355                 .getMetaData(getEntityResolver())
356                 .getClassDescriptor();
357         ObjEntity oe = descriptor.getEntity();
358
359         PropertyVisitor visitor = new PropertyVisitor() {
360
361             public boolean visitAttribute(AttributeProperty property) {
362                 ObjAttribute oa = property.getAttribute();
363                 Iterator JavaDoc dbPathIterator = oa.getDbPathIterator();
364                 while (dbPathIterator.hasNext()) {
365                     Object JavaDoc pathPart = dbPathIterator.next();
366                     if (pathPart instanceof DbRelationship) {
367                         DbRelationship rel = (DbRelationship) pathPart;
368                         dbRelationshipAdded(rel);
369                     }
370                     else if (pathPart instanceof DbAttribute) {
371                         DbAttribute dbAttr = (DbAttribute) pathPart;
372                         if (dbAttr == null) {
373                             throw new CayenneRuntimeException(
374                                     "ObjAttribute has no DbAttribute: " + oa.getName());
375                         }
376
377                         appendColumn(columns, oa, dbAttr, attributes, null);
378                     }
379                 }
380                 return true;
381             }
382
383             public boolean visitToMany(ToManyProperty property) {
384                 visitRelationship(property);
385                 return true;
386             }
387
388             public boolean visitToOne(ToOneProperty property) {
389                 visitRelationship(property);
390                 return true;
391             }
392
393             private void visitRelationship(ArcProperty property) {
394                 ObjRelationship rel = property.getRelationship();
395                 DbRelationship dbRel = (DbRelationship) rel.getDbRelationships().get(0);
396
397                 List JavaDoc joins = dbRel.getJoins();
398                 int len = joins.size();
399                 for (int i = 0; i < len; i++) {
400                     DbJoin join = (DbJoin) joins.get(i);
401                     DbAttribute src = join.getSource();
402                     appendColumn(columns, null, src, attributes, null);
403                 }
404             }
405         };
406
407         if (query.isResolvingInherited()) {
408             descriptor.visitAllProperties(visitor);
409         }
410         else {
411             descriptor.visitProperties(visitor);
412         }
413
414         // add remaining needed attrs from DbEntity
415
DbEntity table = getRootDbEntity();
416         Iterator JavaDoc pk = table.getPrimaryKey().iterator();
417         while (pk.hasNext()) {
418             DbAttribute dba = (DbAttribute) pk.next();
419             appendColumn(columns, null, dba, attributes, null);
420         }
421
422         // special handling of a disjoint query...
423

424         // TODO, Andrus 11/17/2005 - resultPath mechanism is generic and should probably
425
// be moved in the superclass (SelectQuery), replacing customDbAttributes.
426

427         if (query instanceof PrefetchSelectQuery) {
428
429             Iterator JavaDoc extraPaths = ((PrefetchSelectQuery) query)
430                     .getResultPaths()
431                     .iterator();
432
433             // for each relationship path add closest FK or PK, for each attribute path,
434
// add specified column
435
while (extraPaths.hasNext()) {
436
437                 String JavaDoc path = (String JavaDoc) extraPaths.next();
438                 Expression pathExp = oe.translateToDbPath(Expression.fromString(path));
439
440                 Iterator JavaDoc it = table.resolvePathComponents(pathExp);
441
442                 // add joins and find terminating element
443
Object JavaDoc pathComponent = null;
444                 while (it.hasNext()) {
445                     pathComponent = it.next();
446
447                     // do not add join for the last DB Rel
448
if (it.hasNext() && pathComponent instanceof DbRelationship) {
449                         dbRelationshipAdded((DbRelationship) pathComponent);
450                     }
451                 }
452
453                 String JavaDoc labelPrefix = pathExp.toString().substring("db:".length());
454
455                 // process terminating element
456
if (pathComponent instanceof DbAttribute) {
457
458                     // label prefix already includes relationship name
459
appendColumn(
460                             columns,
461                             null,
462                             (DbAttribute) pathComponent,
463                             attributes,
464                             labelPrefix);
465                 }
466                 else if (pathComponent instanceof DbRelationship) {
467                     DbRelationship relationship = (DbRelationship) pathComponent;
468
469                     // add last join
470
if (relationship.isToMany()) {
471                         dbRelationshipAdded(relationship);
472                     }
473
474                     Iterator JavaDoc joins = relationship.getJoins().iterator();
475                     while (joins.hasNext()) {
476                         DbJoin j = (DbJoin) joins.next();
477
478                         DbAttribute attribute = relationship.isToMany()
479                                 ? j.getTarget()
480                                 : j.getSource();
481
482                         // note that we my select a source attribute, but label it as
483
// target for simplified snapshot processing
484
appendColumn(columns, null, attribute, attributes, labelPrefix
485                                 + '.'
486                                 + j.getTargetName());
487                     }
488                 }
489             }
490         }
491
492         // handle joint prefetches directly attached to this query...
493
if (query.getPrefetchTree() != null) {
494
495             Iterator JavaDoc jointPrefetches = query
496                     .getPrefetchTree()
497                     .adjacentJointNodes()
498                     .iterator();
499
500             while (jointPrefetches.hasNext()) {
501                 PrefetchTreeNode prefetch = (PrefetchTreeNode) jointPrefetches.next();
502
503                 // for each prefetch add all joins plus columns from the target entity
504
Expression prefetchExp = Expression.fromString(prefetch.getPath());
505                 Expression dbPrefetch = oe.translateToDbPath(prefetchExp);
506
507                 Iterator JavaDoc it = table.resolvePathComponents(dbPrefetch);
508
509                 DbRelationship r = null;
510                 while (it.hasNext()) {
511                     r = (DbRelationship) it.next();
512                     dbRelationshipAdded(r);
513                 }
514
515                 if (r == null) {
516                     throw new CayenneRuntimeException("Invalid joint prefetch '"
517                             + prefetch
518                             + "' for entity: "
519                             + oe.getName());
520                 }
521
522                 // add columns from the target entity, skipping those that are an FK to
523
// source entity
524

525                 Collection JavaDoc skipColumns = Collections.EMPTY_LIST;
526                 if (r.getSourceEntity() == table) {
527                     skipColumns = new ArrayList JavaDoc(2);
528                     Iterator JavaDoc joins = r.getJoins().iterator();
529                     while (joins.hasNext()) {
530                         DbJoin join = (DbJoin) joins.next();
531                         if (attributes.contains(join.getSource())) {
532                             skipColumns.add(join.getTarget());
533                         }
534                     }
535                 }
536
537                 // go via target OE to make sure that Java types are mapped correctly...
538
ObjRelationship targetRel = (ObjRelationship) prefetchExp.evaluate(oe);
539                 Iterator JavaDoc targetObjAttrs = targetRel
540                         .getTargetEntity()
541                         .getAttributes()
542                         .iterator();
543
544                 String JavaDoc labelPrefix = dbPrefetch.toString().substring("db:".length());
545                 while (targetObjAttrs.hasNext()) {
546                     ObjAttribute oa = (ObjAttribute) targetObjAttrs.next();
547                     Iterator JavaDoc dbPathIterator = oa.getDbPathIterator();
548                     while (dbPathIterator.hasNext()) {
549                         Object JavaDoc pathPart = dbPathIterator.next();
550                         if (pathPart instanceof DbRelationship) {
551                             DbRelationship rel = (DbRelationship) pathPart;
552                             dbRelationshipAdded(rel);
553                         }
554                         else if (pathPart instanceof DbAttribute) {
555                             DbAttribute attribute = (DbAttribute) pathPart;
556                             if (attribute == null) {
557                                 throw new CayenneRuntimeException(
558                                         "ObjAttribute has no DbAttribute: "
559                                                 + oa.getName());
560                             }
561
562                             if (!skipColumns.contains(attribute)) {
563                                 appendColumn(
564                                         columns,
565                                         oa,
566                                         attribute,
567                                         attributes,
568                                         labelPrefix + '.' + attribute.getName());
569                             }
570                         }
571                     }
572                 }
573
574                 // append remaining target attributes such as keys
575
Iterator JavaDoc targetAttributes = r
576                         .getTargetEntity()
577                         .getAttributes()
578                         .iterator();
579                 while (targetAttributes.hasNext()) {
580                     DbAttribute attribute = (DbAttribute) targetAttributes.next();
581                     if (!skipColumns.contains(attribute)) {
582                         appendColumn(columns, null, attribute, attributes, labelPrefix
583                                 + '.'
584                                 + attribute.getName());
585                     }
586                 }
587             }
588         }
589
590         return columns;
591     }
592
593     /**
594      * Appends custom columns from SelectQuery to the provided list.
595      */

596     List JavaDoc appendCustomColumns(List JavaDoc columns, SelectQuery query) {
597
598         List JavaDoc customAttributes = query.getCustomDbAttributes();
599         DbEntity table = getRootDbEntity();
600         int len = customAttributes.size();
601
602         for (int i = 0; i < len; i++) {
603             DbAttribute attribute = (DbAttribute) table
604                     .getAttribute((String JavaDoc) customAttributes.get(i));
605             if (attribute == null) {
606                 throw new CayenneRuntimeException("Attribute does not exist: "
607                         + customAttributes.get(i));
608             }
609
610             String JavaDoc alias = aliasForTable((DbEntity) attribute.getEntity());
611             columns.add(new ColumnDescriptor(attribute, alias));
612         }
613
614         return columns;
615     }
616
617     private void appendColumn(
618             List JavaDoc columns,
619             ObjAttribute objAttribute,
620             DbAttribute attribute,
621             Set JavaDoc skipSet,
622             String JavaDoc label) {
623
624         if (skipSet.add(attribute)) {
625             String JavaDoc alias = aliasForTable((DbEntity) attribute.getEntity());
626             ColumnDescriptor column = (objAttribute != null) ? new ColumnDescriptor(
627                     objAttribute,
628                     attribute,
629                     alias) : new ColumnDescriptor(attribute, alias);
630
631             if (label != null) {
632                 column.setLabel(label);
633             }
634
635             columns.add(column);
636
637             // TODO: andrus, 5/7/2006 - replace 'columns' collection with this map, as it
638
// is redundant
639
defaultAttributesByColumn.put(column, objAttribute);
640         }
641         else if (objAttribute != null) {
642
643             // record ObjAttribute override
644
for (int i = 0; i < columns.size(); i++) {
645                 ColumnDescriptor column = (ColumnDescriptor) columns.get(i);
646                 if (attribute.getName().equals(column.getName())) {
647                   
648                     // kick out the original attribute
649
ObjAttribute original = (ObjAttribute) defaultAttributesByColumn
650                             .remove(column);
651
652                     if (original != null) {
653                         if (attributeOverrides == null) {
654                             attributeOverrides = new HashMap JavaDoc();
655                         }
656                         
657                         attributeOverrides.put(original, column);
658                         column.setJavaClass(Void.TYPE.getName());
659                     }
660
661                     break;
662                 }
663             }
664         }
665     }
666
667     private void appendGroupBy(StringBuffer JavaDoc queryBuf, int index) {
668         DbAttribute column = (DbAttribute) groupByList.get(index);
669         String JavaDoc alias = aliasForTable((DbEntity) column.getEntity());
670         queryBuf.append(column.getAliasedName(alias));
671     }
672
673     private void appendTable(StringBuffer JavaDoc queryBuf, int index) {
674         DbEntity ent = (DbEntity) tableList.get(index);
675         queryBuf.append(ent.getFullyQualifiedName());
676         // The alias should be the alias from the same index in aliasList, not that
677
// returned by aliasForTable.
678
queryBuf.append(' ').append((String JavaDoc) aliasList.get(index));
679     }
680
681     private void appendJoins(StringBuffer JavaDoc queryBuf, int index) {
682         DbRelationship rel = (DbRelationship) dbRelList.get(index);
683         String JavaDoc srcAlias = aliasForTable((DbEntity) rel.getSourceEntity());
684         String JavaDoc targetAlias = (String JavaDoc) aliasLookup.get(rel);
685
686         boolean andFlag = false;
687
688         List JavaDoc joins = rel.getJoins();
689         int len = joins.size();
690         for (int i = 0; i < len; i++) {
691             DbJoin join = (DbJoin) joins.get(i);
692
693             if (andFlag) {
694                 queryBuf.append(" AND ");
695             }
696             else {
697                 andFlag = true;
698             }
699
700             queryBuf.append(srcAlias).append('.').append(join.getSourceName()).append(
701                     " = ").append(targetAlias).append('.').append(join.getTargetName());
702         }
703     }
704
705     /**
706      * Stores a new relationship in an internal list. Later it will be used to create
707      * joins to relationship destination table.
708      */

709     public void dbRelationshipAdded(DbRelationship rel) {
710         if (rel.isToMany()) {
711             forcingDistinct = true;
712         }
713
714         String JavaDoc existAlias = (String JavaDoc) aliasLookup.get(rel);
715
716         if (existAlias == null) {
717             dbRelList.add(rel);
718
719             // add alias for the destination table of the relationship
720
String JavaDoc newAlias = newAliasForTable((DbEntity) rel.getTargetEntity());
721             aliasLookup.put(rel, newAlias);
722         }
723     }
724
725     /**
726      * Sets up and returns a new alias for a speciafied table.
727      */

728     protected String JavaDoc newAliasForTable(DbEntity ent) {
729         if (ent instanceof DerivedDbEntity) {
730             ent = ((DerivedDbEntity) ent).getParentEntity();
731         }
732
733         String JavaDoc newAlias = "t" + aliasCounter++;
734         tableList.add(ent);
735         aliasList.add(newAlias);
736         return newAlias;
737     }
738
739     public String JavaDoc aliasForTable(DbEntity ent, DbRelationship rel) {
740         return (String JavaDoc) aliasLookup.get(rel);
741     }
742
743     /**
744      * Overrides superclass implementation. Will return an alias that should be used for a
745      * specified DbEntity in the query (or null if this DbEntity is not included in the
746      * FROM clause).
747      */

748     public String JavaDoc aliasForTable(DbEntity ent) {
749         if (ent instanceof DerivedDbEntity) {
750             ent = ((DerivedDbEntity) ent).getParentEntity();
751         }
752
753         int entIndex = tableList.indexOf(ent);
754         if (entIndex >= 0) {
755             return (String JavaDoc) aliasList.get(entIndex);
756         }
757         else {
758             StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
759             msg.append("Alias not found, DbEntity: '").append(
760                     ent != null ? ent.getName() : "<null entity>").append(
761                     "'\nExisting aliases:");
762
763             int len = aliasList.size();
764             for (int i = 0; i < len; i++) {
765                 String JavaDoc dbeName = (tableList.get(i) != null) ? ((DbEntity) tableList
766                         .get(i)).getName() : "<null entity>";
767                 msg.append("\n").append(aliasList.get(i)).append(" => ").append(dbeName);
768             }
769
770             throw new CayenneRuntimeException(msg.toString());
771         }
772     }
773
774     /**
775      * Always returns true.
776      */

777     public boolean supportsTableAliases() {
778         return true;
779     }
780 }
781
Popular Tags