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