KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > jdbc > EJBQLConditionTranslator


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 package org.apache.cayenne.access.jdbc;
20
21 import java.math.BigDecimal JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.apache.cayenne.ObjectId;
28 import org.apache.cayenne.Persistent;
29 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
30 import org.apache.cayenne.ejbql.EJBQLException;
31 import org.apache.cayenne.ejbql.EJBQLExpression;
32 import org.apache.cayenne.ejbql.parser.EJBQLPath;
33 import org.apache.cayenne.ejbql.parser.EJBQLPositionalInputParameter;
34
35 /**
36  * @since 3.0
37  * @author Andrus Adamchik
38  */

39 class EJBQLConditionTranslator extends EJBQLBaseVisitor {
40
41     private EJBQLTranslationContext context;
42
43     private List JavaDoc multiColumnOperands;
44
45     EJBQLConditionTranslator(EJBQLTranslationContext context) {
46         this.context = context;
47     }
48
49     void addMultiColumnOperand(EJBQLMultiColumnOperand operand) {
50         if (multiColumnOperands == null) {
51             multiColumnOperands = new ArrayList JavaDoc(2);
52         }
53
54         multiColumnOperands.add(operand);
55     }
56
57     public boolean visitAnd(EJBQLExpression expression, int finishedChildIndex) {
58         afterChild(expression, " AND", finishedChildIndex);
59         return true;
60     }
61
62     public boolean visitBetween(EJBQLExpression expression, int finishedChildIndex) {
63         switch (finishedChildIndex) {
64             case 0:
65                 if (expression.isNegated()) {
66                     context.append(" NOT");
67                 }
68                 context.append(" BETWEEN");
69                 break;
70             case 1:
71                 context.append(" AND");
72                 break;
73         }
74
75         return true;
76     }
77
78     public boolean visitOr(EJBQLExpression expression, int finishedChildIndex) {
79         afterChild(expression, " OR", finishedChildIndex);
80         return true;
81     }
82
83     public boolean visitEquals(EJBQLExpression expression, int finishedChildIndex) {
84         switch (finishedChildIndex) {
85             case 0:
86                 context.append(" =");
87                 break;
88             case 1:
89                 // check multicolumn match condition and undo op insertion and append it
90
// from scratch if needed
91
if (multiColumnOperands != null) {
92
93                     if (multiColumnOperands.size() != 2) {
94                         throw new EJBQLException(
95                                 "Invalid multi-column equals expression. Expected 2 multi-column operands, got "
96                                         + multiColumnOperands.size());
97                     }
98
99                     context.trim(2);
100
101                     EJBQLMultiColumnOperand lhs = (EJBQLMultiColumnOperand) multiColumnOperands
102                             .get(0);
103                     EJBQLMultiColumnOperand rhs = (EJBQLMultiColumnOperand) multiColumnOperands
104                             .get(1);
105
106                     Iterator JavaDoc it = lhs.getKeys().iterator();
107                     while (it.hasNext()) {
108                         Object JavaDoc key = it.next();
109
110                         lhs.appendValue(key);
111                         context.append(" =");
112                         rhs.appendValue(key);
113
114                         if (it.hasNext()) {
115                             context.append(" AND");
116                         }
117                     }
118
119                     multiColumnOperands = null;
120                 }
121
122                 break;
123         }
124
125         return true;
126     }
127
128     public boolean visitNamedInputParameter(EJBQLExpression expression) {
129         String JavaDoc parameter = context.bindNamedParameter(expression.getText());
130         processParameter(parameter);
131         return true;
132     }
133
134     public boolean visitNot(EJBQLExpression expression) {
135         context.append(" NOT");
136         return true;
137     }
138
139     public boolean visitNotEquals(EJBQLExpression expression, int finishedChildIndex) {
140         switch (finishedChildIndex) {
141             case 0:
142                 context.append(" <>");
143                 break;
144             case 1:
145                 // check multicolumn match condition and undo op insertion and append it
146
// from scratch if needed
147
if (multiColumnOperands != null) {
148
149                     if (multiColumnOperands.size() != 2) {
150                         throw new EJBQLException(
151                                 "Invalid multi-column equals expression. Expected 2 multi-column operands, got "
152                                         + multiColumnOperands.size());
153                     }
154
155                     context.trim(3);
156
157                     EJBQLMultiColumnOperand lhs = (EJBQLMultiColumnOperand) multiColumnOperands
158                             .get(0);
159                     EJBQLMultiColumnOperand rhs = (EJBQLMultiColumnOperand) multiColumnOperands
160                             .get(1);
161
162                     Iterator JavaDoc it = lhs.getKeys().iterator();
163                     while (it.hasNext()) {
164                         Object JavaDoc key = it.next();
165
166                         lhs.appendValue(key);
167                         context.append(" <>");
168                         rhs.appendValue(key);
169
170                         if (it.hasNext()) {
171                             context.append(" OR");
172                         }
173                     }
174
175                     multiColumnOperands = null;
176                 }
177
178                 break;
179         }
180         return true;
181     }
182
183     public boolean visitGreaterThan(EJBQLExpression expression, int finishedChildIndex) {
184         if (finishedChildIndex == 0) {
185             context.append(" >");
186         }
187
188         return true;
189     }
190
191     public boolean visitGreaterOrEqual(EJBQLExpression expression, int finishedChildIndex) {
192         if (finishedChildIndex == 0) {
193             context.append(" >=");
194         }
195
196         return true;
197     }
198
199     public boolean visitLessOrEqual(EJBQLExpression expression, int finishedChildIndex) {
200         if (finishedChildIndex == 0) {
201             context.append(" <=");
202         }
203
204         return true;
205     }
206
207     public boolean visitLessThan(EJBQLExpression expression, int finishedChildIndex) {
208         if (finishedChildIndex == 0) {
209             context.append(" <");
210         }
211
212         return true;
213     }
214
215     public boolean visitLike(EJBQLExpression expression, int finishedChildIndex) {
216         if (finishedChildIndex == 0) {
217             if (expression.isNegated()) {
218                 context.append(" NOT");
219             }
220             context.append(" LIKE");
221         }
222
223         return true;
224     }
225
226     protected void afterChild(EJBQLExpression e, String JavaDoc text, int childIndex) {
227         if (childIndex >= 0) {
228             if (childIndex + 1 < e.getChildrenCount()) {
229                 context.append(text);
230             }
231         }
232     }
233
234     public boolean visitPath(EJBQLPath expression, int finishedChildIndex) {
235
236         expression.visit(new EJBQLPathTranslator(context) {
237
238             protected void appendMultiColumnPath(EJBQLMultiColumnOperand operand) {
239                 EJBQLConditionTranslator.this.addMultiColumnOperand(operand);
240             }
241         });
242         return false;
243     }
244
245     public boolean visitIntegerLiteral(EJBQLExpression expression) {
246         if (expression.getText() == null) {
247             context.append("null");
248         }
249         else {
250             Object JavaDoc value;
251
252             try {
253                 value = new Integer JavaDoc(expression.getText());
254             }
255             catch (NumberFormatException JavaDoc nfex) {
256                 throw new EJBQLException("Invalid integer: " + expression.getText());
257             }
258
259             String JavaDoc var = context.bindParameter(value);
260             context.append(" #bind($").append(var).append(" 'INTEGER')");
261         }
262         return true;
263     }
264
265     public boolean visitDecimalLiteral(EJBQLExpression expression) {
266         if (expression.getText() == null) {
267             context.append("null");
268         }
269         else {
270             Object JavaDoc value;
271
272             try {
273                 value = new BigDecimal JavaDoc(expression.getText());
274             }
275             catch (NumberFormatException JavaDoc nfex) {
276                 throw new EJBQLException("Invalid decimal: " + expression.getText());
277             }
278
279             String JavaDoc var = context.bindParameter(value);
280             context.append(" #bind($").append(var).append(" 'DECIMAL')");
281         }
282         return true;
283     }
284
285     public boolean visitPatternValue(EJBQLExpression expression) {
286         // TODO: andrus 3/25/2007 - implement me
287
return true;
288     }
289
290     public boolean visitIsNull(EJBQLExpression expression, int finishedChildIndex) {
291         if (finishedChildIndex == 0) {
292             context.append(expression.isNegated() ? " IS NOT NULL" : " IS NULL");
293         }
294
295         return true;
296     }
297
298     public boolean visitPositionalInputParameter(EJBQLPositionalInputParameter expression) {
299
300         String JavaDoc parameter = context.bindPositionalParameter(expression.getPosition());
301         processParameter(parameter);
302         return true;
303     }
304
305     public boolean visitStringLiteral(EJBQLExpression expression) {
306         if (expression.getText() == null) {
307             context.append("null");
308         }
309         else {
310             // note that String Literal text is already wrapped in single quotes, with
311
// quotes that are part of the string escaped.
312
context.append(" #bind(").append(expression.getText()).append(" 'VARCHAR')");
313         }
314         return true;
315     }
316
317     private void processParameter(String JavaDoc boundName) {
318         Object JavaDoc object = context.getBoundParameter(boundName);
319
320         Map JavaDoc map = null;
321         if (object instanceof Persistent) {
322             map = ((Persistent) object).getObjectId().getIdSnapshot();
323         }
324         else if (object instanceof ObjectId) {
325             map = ((ObjectId) object).getIdSnapshot();
326         }
327         else if (object instanceof Map JavaDoc) {
328             map = (Map JavaDoc) object;
329         }
330
331         if (map != null) {
332             if (map.size() == 1) {
333                 context.rebindParameter(boundName, map.values().iterator().next());
334             }
335             else {
336                 addMultiColumnOperand(EJBQLMultiColumnOperand.getObjectOperand(
337                         context,
338                         map));
339                 return;
340             }
341         }
342
343         if (object != null) {
344             context.append(" #bind($").append(boundName).append(")");
345         }
346         else {
347             // this is a hack to prevent execptions on DB's like Derby for expressions
348
// "X = NULL". The 'VARCHAR' parameter is totally bogus, but seems to work on
349
// all tested DB's... Also note what JPA spec, chapter 4.11 says: "Comparison
350
// or arithmetic operations with a NULL value always yield an unknown value."
351

352             // TODO: andrus 6/28/2007 Ideally we should track the type of the current
353
// expression to provide a meaningful type.
354
context.append(" #bind($").append(boundName).append(" 'VARCHAR')");
355         }
356     }
357 }
358
Popular Tags