1 package org.apache.torque.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.Serializable;
20 import java.util.List;
21
22 import org.apache.torque.TorqueException;
23 import org.apache.torque.adapter.DB;
24 import org.apache.torque.map.DatabaseMap;
25
26 /***
27 * Factored out code that is used to generate Join Code. This code comes
28 * from BasePeer and is put here to reduce complexity in the BasePeer class.
29 * You should not use the methods here directly!
30 *
31 * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
32 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
33 * @version $Id: JoinBuilder.java 239636 2005-08-24 12:38:09Z henning $
34 */
35 public abstract class JoinBuilder
36 implements Serializable
37 {
38 /***
39 * adds the Joins from the criteria to the query
40 * @param criteria the criteria from which the Joins are taken
41 * @param query the query to which the Joins should be added
42 * @throws TorqueException if the Joins can not be processed
43 */
44 public static final void processJoins(
45 final DB db,
46 final DatabaseMap dbMap,
47 final Criteria criteria,
48 final Query query)
49 throws TorqueException
50 {
51 List criteriaJoins = criteria.getJoins();
52
53 if (criteriaJoins == null)
54 {
55 return;
56 }
57
58 UniqueList queryFromClause = query.getFromClause();
59 UniqueList queryWhereClause = query.getWhereClause();
60
61 for (int i = 0; i < criteriaJoins.size(); i++)
62 {
63 Criteria.Join join = (Criteria.Join) criteriaJoins.get(i);
64 String leftColumn = join.getLeftColumn();
65 String rightColumn = join.getRightColumn();
66
67
68 if (leftColumn.indexOf('.') == -1)
69 {
70 SQLBuilder.throwMalformedColumnNameException("join", leftColumn);
71 }
72 if (rightColumn.indexOf('.') == -1)
73 {
74 SQLBuilder.throwMalformedColumnNameException("join", rightColumn);
75 }
76
77
78
79
80 int dot = leftColumn.lastIndexOf('.');
81 String leftTableName = leftColumn.substring(0, dot);
82
83 leftTableName =
84 SQLBuilder.getTableNameForFromClause(leftTableName, criteria);
85
86 dot = rightColumn.lastIndexOf('.');
87 String rightTableName = rightColumn.substring(0, dot);
88 String dbTableName
89 = criteria.getTableForAlias(rightTableName);
90
91 if (dbTableName == null)
92 {
93 dbTableName = rightTableName;
94 }
95
96 String columnName = rightColumn.substring(
97 dot + 1,
98 rightColumn.length());
99
100 boolean ignoreCase = (criteria.isIgnoreCase()
101 && (dbMap
102 .getTable(dbTableName)
103 .getColumn(columnName)
104 .getType()
105 instanceof String));
106
107 rightTableName = SQLBuilder.getTableNameForFromClause(
108 rightTableName, criteria);
109
110
111
112 SqlEnum joinType = join.getJoinType();
113
114 if (joinType == null)
115 {
116
117
118 if (!SQLBuilder.fromClauseContainsTableName(
119 queryFromClause,
120 leftTableName))
121 {
122 Query.FromElement fromElement
123 = new Query.FromElement(
124 leftTableName, null, null);
125 queryFromClause.add(fromElement);
126 }
127 if (!SQLBuilder.fromClauseContainsTableName(
128 queryFromClause,
129 rightTableName))
130 {
131 Query.FromElement fromElement
132 = new Query.FromElement(
133 rightTableName, null, null);
134 queryFromClause.add(fromElement);
135 }
136 queryWhereClause.add(
137 SqlExpression.buildInnerJoin(
138 leftColumn, rightColumn, ignoreCase, db));
139 }
140 else
141 {
142
143
144
145
146 if (!SQLBuilder.fromClauseContainsTableName(
147 queryFromClause,
148 rightTableName))
149 {
150 if (!SQLBuilder.fromClauseContainsTableName(
151 queryFromClause,
152 leftTableName))
153 {
154 Query.FromElement fromElement
155 = new Query.FromElement(
156 leftTableName, null, null);
157 queryFromClause.add(fromElement);
158 }
159
160 Query.FromElement fromElement
161 = new Query.FromElement(
162 rightTableName, joinType,
163 SqlExpression.buildInnerJoin(
164 leftColumn, rightColumn,
165 ignoreCase, db));
166 queryFromClause.add(fromElement);
167 }
168 else
169 {
170 if (SQLBuilder.fromClauseContainsTableName(
171 queryFromClause,
172 leftTableName))
173 {
174
175
176 throw new TorqueException(
177 "Unable to create a " + joinType
178 + "because both table names "
179 + leftTableName + " and " + rightTableName
180 + " are already in use. "
181 + "Try to create an(other) alias.");
182 }
183
184
185
186 Query.FromElement fromElement
187 = new Query.FromElement(
188 leftTableName, reverseJoinType(joinType),
189 SqlExpression.buildInnerJoin(
190 rightColumn, leftColumn,
191 ignoreCase, db));
192 queryFromClause.add(fromElement);
193 }
194 }
195 }
196 }
197
198 /***
199 * returns the reversed Join type, i.e. the join type which would produce
200 * the same result if also the joined tables were exchanged:
201 * Example:<br />
202 * table_a left join table_b <br />
203 * produces the same result as <br />
204 * table_b right join table_a<br />
205 * So "left join" is the reverse of "right join"
206 * @param joinType the join type to be reversed
207 * @return the reversed join type
208 */
209 private static final SqlEnum reverseJoinType(
210 final SqlEnum joinType)
211 {
212 if (SqlEnum.LEFT_JOIN.equals(joinType))
213 {
214 return SqlEnum.RIGHT_JOIN;
215 }
216 else if (SqlEnum.RIGHT_JOIN.equals(joinType))
217 {
218 return SqlEnum.LEFT_JOIN;
219 }
220 else
221 {
222 return joinType;
223 }
224 }
225 }