KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdbc > query > JDOQLNodeToSqlExp


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdbc.query;
13
14 import com.versant.core.jdo.query.*;
15 import com.versant.core.jdbc.sql.exp.*;
16 import com.versant.core.jdbc.sql.exp.AggregateCountStarExp;
17 import com.versant.core.jdbc.sql.conv.DummyPreparedStmt;
18 import com.versant.core.jdbc.metadata.*;
19 import com.versant.core.common.BindingSupportImpl;
20 import com.versant.core.metadata.MDStatics;
21 import com.versant.core.metadata.MDStaticUtils;
22 import com.versant.core.metadata.ClassMetaData;
23
24 import java.sql.SQLException JavaDoc;
25
26 /**
27  * Walks a JDOQL Node trees to produce SqlExp trees.
28  */

29 public class JDOQLNodeToSqlExp extends NodeVisitorAdapter {
30
31     private final JdbcJDOQLCompiler comp;
32
33     /**
34      * This instance can convert Node's that do not need to access a
35      * JdbcQueryCompiler to SqlExp.
36      */

37     public static final JDOQLNodeToSqlExp INSTANCE = new JDOQLNodeToSqlExp();
38
39     /**
40      * Information passed down from a Node to its children via arrive
41      * callback mechanism.
42      */

43     private static class Context {
44
45         public SelectExp root;
46         public SqlExp leftSibling;
47         public int method;
48         public Node args;
49
50         public Context(SelectExp root) {
51             this.root = root;
52         }
53
54         public Context(SelectExp root, SqlExp leftSibling, int method, Node args) {
55             this.root = root;
56             this.leftSibling = leftSibling;
57             this.method = method;
58             this.args = args;
59         }
60     }
61
62     public JDOQLNodeToSqlExp(JdbcJDOQLCompiler comp) {
63         this.comp = comp;
64     }
65
66     private JDOQLNodeToSqlExp() {
67         this(null);
68     }
69
70     /**
71      * Convert a Node tree to an SqlExp tree.
72      */

73     public SqlExp toSqlExp(Node node, SelectExp root, SqlExp leftSibling,
74             int method, Node args) {
75         return (SqlExp)node.arrive(this, new Context(root, leftSibling,
76                 method, args));
77     }
78
79     protected Object JavaDoc defaultArrive(Node node, Object JavaDoc msg) {
80         throw BindingSupportImpl.getInstance().internal("Not implemented: " +
81                 node.getClass());
82     }
83
84     public Object JavaDoc arriveFieldNavNode(FieldNavNode node, Object JavaDoc msg) {
85         Context ctx = (Context)msg;
86         SelectExp root = ctx.root;
87         if (node.var == null) {
88             JdbcField jdbcField = (JdbcField)node.fmd.storeField;
89             JdbcClass targetClass = (JdbcClass)node.targetClass.storeClass;
90             SelectExp se;
91             Join j = root.findJoin(jdbcField);
92             if (j == null) {
93                 SelectExp leftTableSE = root.findTable(jdbcField.mainTable);
94                 if (leftTableSE == null) {
95                     throw BindingSupportImpl.getInstance().runtime(
96                             "No join to '"
97                             + jdbcField.mainTable + "' for nav field '" + jdbcField.fmd.name);
98                 }
99
100                 se = new SelectExp();
101                 se.table = targetClass.table;
102                 se.jdbcField = jdbcField;
103                 if (jdbcField instanceof JdbcPolyRefField) {
104                     JdbcPolyRefField pf = (JdbcPolyRefField)jdbcField;
105                     j = leftTableSE.addJoin(pf.refCols, se.table.pk, se);
106                     // add a condition to check that the class-id column of
107
// the polyref matches the type used in the cast
108
j.appendJoinExp(
109                             pf.createClassIdMatchExp(root, targetClass.cmd));
110                 } else {
111                     j = leftTableSE.addJoin(jdbcField.mainTableCols,
112                             se.table.pk, se);
113                     if (node.cast != null && targetClass.cmd.isInHeirachy()) {
114                         //join to basetable for classIdJoin
115
if (targetClass.classIdCol != null && targetClass.classIdCol.table != se.table) {
116                             SelectExp bSe = (SelectExp)root.findTable(targetClass.classIdCol.table);
117                             if (bSe == null) {
118                                 bSe = new SelectExp();
119                                 bSe.outer = se.outer;
120                                 bSe.table = targetClass.classIdCol.table;
121                                 j = se.addJoin(se.table.pk, bSe.table.pk, bSe);
122                             }
123                         }
124
125                         // downcast so join must include code to check the
126
// class-id column of the target table
127
j.appendJoinExp(targetClass.getCheckClassIdExp(se));
128                     }
129                 }
130             } else {
131                 se = j.selectExp;
132             }
133             if (node.childList == null) {
134                 return null;
135             } else {
136                 return toSqlExp(node.childList, se, ctx.leftSibling,
137                         ctx.method, ctx.args);
138             }
139         } else {
140             return toSqlExp(node.childList, (SelectExp)node.var.getStoreExtent(),
141                     ctx.leftSibling, ctx.method, ctx.args);
142         }
143     }
144
145     public Object JavaDoc arriveLiteralNode(LiteralNode node, Object JavaDoc msg) {
146         Context ctx = (Context)msg;
147         SqlExp leftSibling = ctx.leftSibling;
148         String JavaDoc value = node.value;
149         int t;
150         switch (node.type) {
151             case LiteralNode.TYPE_OTHER: t = LiteralExp.TYPE_OTHER; break;
152             case LiteralNode.TYPE_STRING: t = LiteralExp.TYPE_STRING; break;
153             case LiteralNode.TYPE_NULL: t = LiteralExp.TYPE_NULL; break;
154             case LiteralNode.TYPE_BOOLEAN:
155                 t = LiteralExp.TYPE_OTHER;
156
157                 /**
158                  * The idea here is to convert the boolean literal 'true' or
159                  * 'false' via the converter on the field that it is being compared to.
160                  * If there is no converter on the field then we expect a 'true'
161                  * or 'false' constant to work.
162                  */

163                 if (ctx.leftSibling instanceof ColumnExp) {
164                     ColumnExp cExp = (ColumnExp)leftSibling;
165                     if (cExp.col.converter == null) break;
166                     DummyPreparedStmt pstmt = new DummyPreparedStmt();
167                     try {
168                         cExp.col.converter.set(pstmt, 0, cExp.col,
169                                 new Boolean JavaDoc(value));
170                     } catch (SQLException JavaDoc e) {
171                         //ignore
172
}
173                     value = pstmt.value;
174                     if (pstmt.toQuote) {
175                         t = LiteralExp.TYPE_STRING;
176                     } else {
177                         t = LiteralExp.TYPE_OTHER;
178                     }
179                 }
180                 break;
181             case LiteralNode.TYPE_CHAR:
182             case LiteralNode.TYPE_DOUBLE:
183             case LiteralNode.TYPE_LONG: t = LiteralExp.TYPE_OTHER; break;
184             default:
185                 throw BindingSupportImpl.getInstance().internal(
186                     "Unknown literal type: " + node.type);
187         }
188
189         LiteralExp ans = new LiteralExp(t, value);
190         if (node.type == LiteralNode.TYPE_NULL) {
191             // Create a list of LiteralExp's with one entry for each expression
192
// on the left hand side. This is to handle references to composite
193
// pk classes.
194
for (SqlExp pos = ans; (leftSibling = leftSibling.next) != null; ) {
195                 pos = pos.next = new LiteralExp(t, value);
196             }
197         }
198         return ans;
199     }
200
201     public Object JavaDoc arriveMethodNode(MethodNode node, Object JavaDoc msg) {
202         Context ctx = (Context)msg;
203         SelectExp root = ctx.root;
204         int method = node.getMethod();
205         Node childList = node.childList;
206         switch (method) {
207             case MethodNode.STARTS_WITH: return toSqlLike(childList, method, root, false);
208             case MethodNode.ENDS_WITH: return toSqlLike(childList, method, root, true);
209             case MethodNode.CONTAINS:
210             case MethodNode.CONTAINS_KEY: return toSqlContains(childList, method, root);
211             case MethodNode.IS_EMPTY: return toSqlIsEmpty(childList, root);
212             case MethodNode.TO_LOWER_CASE: return toSqlToLowerCase(childList, method, root);
213             case MethodNode.SQL: return toSqlInline(childList, method, root);
214         }
215         throw BindingSupportImpl.getInstance().internal("Unknown method: " + method);
216     }
217
218     private SqlExp toSqlInline(Node childList, int method, SelectExp root) {
219         SqlExp left = toSqlExp(childList, root, null, method, null);
220         SqlExp right;
221         if (childList.next != null) {
222             right = toSqlExp(childList.next, root, left, method, null);
223         } else {
224             right = null;
225         }
226         String JavaDoc template;
227         if (right == null) {
228             template = "$1";
229         } else if (right instanceof LiteralExp) {
230             template = ((LiteralExp)right).value;
231         } else {
232             throw BindingSupportImpl.getInstance().invalidOperation("Expected literal expression: " + right);
233         }
234         return new InlineSqlExp(template, left);
235     }
236
237     private SqlExp toSqlLike(Node childList, int method, SelectExp root,
238             boolean endsWith) {
239         SqlExp left = toSqlExp(childList, root, null, method, null);
240         SqlExp right = toSqlExp(childList.next, root, left, method, null);
241         if (right instanceof LiteralExp
242                 && ((LiteralExp)right).type == LiteralExp.TYPE_STRING) {
243             // prepend or append a % to the literal string
244
LiteralExp le = (LiteralExp)right;
245             if (endsWith) le.value = "%" + le.value;
246             else le.value = le.value + "%";
247         } else {
248             // create a BinaryExp to prepend or append %
249
LiteralExp pe = new LiteralExp(LiteralExp.TYPE_STRING, "%");
250             if (endsWith) right = new BinaryOpExp(pe, BinaryOpExp.CONCAT, right);
251             else right = new BinaryOpExp(right, BinaryOpExp.CONCAT, pe);
252         }
253         return new BinaryOpExp(left, BinaryOpExp.LIKE, right);
254     }
255
256     private SqlExp toSqlIsEmpty(Node childList, SelectExp root) {
257         if (childList.next != null) {
258             throw BindingSupportImpl.getInstance().runtime(
259                     "isEmpty() does not accept arguments");
260         }
261         return toSqlExp(childList, root, null, MethodNode.IS_EMPTY, null);
262     }
263
264     private SqlExp toSqlContains(Node childList, int method, SelectExp root) {
265         return toSqlExp(childList, root, null, method, childList.next);
266     }
267
268     private SqlExp toSqlToLowerCase(Node childList, int method, SelectExp root) {
269         if (childList.next != null) {
270             throw BindingSupportImpl.getInstance().runtime(
271                     "toLowerCase() does not accept arguments");
272         }
273         SqlExp left = toSqlExp(childList, root, null, method, null);
274         return new UnaryFunctionExp(left, UnaryFunctionExp.FUNC_TO_LOWER_CASE);
275     }
276
277     public Object JavaDoc arriveFieldNode(FieldNode node, Object JavaDoc msg) {
278         Context ctx = (Context)msg;
279         int method = ctx.method;
280         SelectExp root = ctx.root;
281         Node args = ctx.args;
282         JdbcField jdbcField = (JdbcField)node.fmd.storeField;
283
284         switch (method) {
285             case MethodNode.IS_EMPTY:
286                 return jdbcField.toIsEmptySqlExp(comp, root);
287             case MethodNode.CONTAINS:
288                 return jdbcField.toContainsSqlExp(comp, root, args);
289             case MethodNode.CONTAINS_KEY:
290                 return jdbcField.toContainsKeySqlExp(comp, root, args);
291             case MethodNode.CONTAINS_PARAM:
292                 if (jdbcField.mainTableCols.length > 1) {
293                     throw BindingSupportImpl.getInstance().invalidOperation(
294                             "This is only supported for single column instances");
295                 }
296                 return new CollectionParamExp(jdbcField.toColumnExp(
297                         SelectExp.createJoinToSuperTable(root, jdbcField), true));
298         };
299
300         // This is to detect the scenario where a boolean field is in the jdoql
301
// expression on its own. eg 'booleanField && name == param'
302
if (isUnaryBoolExp(node, jdbcField)) {
303             ColumnExp cExp = jdbcField.toColumnExp(root, true);
304
305             LiteralExp lExp = new LiteralExp();
306             if (cExp.col.converter != null) {
307                 DummyPreparedStmt pstmt = new DummyPreparedStmt();
308                 try {
309                     cExp.col.converter.set(pstmt, 0, cExp.col, new Boolean JavaDoc(true));
310                 } catch (SQLException JavaDoc e) {
311                     //ignore
312
}
313
314                 lExp.value = pstmt.value;
315                 if (pstmt.toQuote) {
316                     lExp.type = LiteralExp.TYPE_STRING;
317                 } else {
318                     lExp.type = LiteralExp.TYPE_OTHER;
319                 }
320                 return new BinaryOpExp(cExp, BinaryOpExp.EQUAL, lExp);
321             } else {
322                 lExp.type = LiteralExp.TYPE_OTHER;
323                 lExp.value = "true";
324                 return new BinaryOpExp(cExp, BinaryOpExp.EQUAL, lExp);
325             }
326         }
327
328         SelectExp fSe = node.useCandidateExtent ? comp.getCandidateSelectExp() : root;
329         ColumnExp columnExp = jdbcField.toColumnExp(SelectExp.createJoinToSuperTable(fSe, jdbcField), true);
330         if (!isPartOfAggregate(node.parent)) columnExp.setColAlias(node.asValue);
331         return columnExp;
332     }
333
334     private static boolean isUnaryBoolExp(Node node, JdbcField jdbcField) {
335         if (isBooleanType(jdbcField) && !(node.parent instanceof OrderNode)) {
336             if (node.parent instanceof FieldNavNode) {
337                 return isUnaryBoolExp(node.parent, jdbcField);
338             } else if ((node.parent instanceof AndNode)
339                     || (node.parent instanceof OrNode)
340                     || (node.parent != null && node.parent.parent == null)) {
341                 return true;
342             }
343         }
344         return false;
345     }
346
347     private static boolean isBooleanType(JdbcField jdbcField) {
348         if (jdbcField == null) return false;
349         return ((jdbcField.fmd.typeCode == MDStatics.BOOLEAN)
350                         || (jdbcField.fmd.typeCode == MDStatics.BOOLEANW));
351     }
352
353     private static boolean isPartOfAggregate(Node n) {
354         if (n == null) return false;
355         if (n instanceof AggregateNode) return true;
356         return isPartOfAggregate(n.parent);
357     }
358
359     public Object JavaDoc arriveEqualNode(EqualNode node, Object JavaDoc msg) {
360         return arriveEqualOrNotEqual(node, msg, BinaryOpExp.EQUAL);
361     }
362
363     public Object JavaDoc arriveLikeNode(LikeNode node, Object JavaDoc msg) {
364         return arriveEqualOrNotEqual(node, msg, BinaryOpExp.LIKE);
365     }
366
367     private Object JavaDoc arriveEqualOrNotEqual(EqualNode node, Object JavaDoc msg, int op) {
368         Context ctx = (Context)msg;
369         SelectExp root = ctx.root;
370
371         // If a field is being compared to a null literal then only put
372
// columns that are not shared in the left expression unless all of
373
// the columns are shared.
374
SqlExp left;
375         Node childList = node.childList;
376         if (isNullLiteral(childList.next) && childList instanceof FieldNode) {
377             JdbcField f = (JdbcField)((FieldNode)childList).fmd.storeField;
378             left = f.toColumnExpForNullLiteralCompare(root);
379         } else {
380             left = toSqlExp(childList, root, null, ctx.method, ctx.args);
381         }
382
383         SqlExp right = toSqlExp(childList.next, root, left, ctx.method, ctx.args);
384         return SqlExp.createBinaryOpExp(left, op, right);
385     }
386
387     private static boolean isNullLiteral(Node n) {
388         return n instanceof LiteralNode
389             && ((LiteralNode)n).type == LiteralNode.TYPE_NULL;
390     }
391
392     public Object JavaDoc arriveNotEqualNode(NotEqualNode node, Object JavaDoc msg) {
393         return arriveEqualOrNotEqual(node, msg, BinaryOpExp.NOT_EQUAL);
394     }
395
396     public Object JavaDoc arriveAndNode(AndNode node, Object JavaDoc msg) {
397         Context ctx = (Context)msg;
398         Node childList = node.childList;
399
400         // Build the list of expressions to be anded together.
401
SqlExp prev = null, first = null;
402         for (Node cn = childList; cn != null;) {
403             SqlExp e = toSqlExp(cn, ctx.root, prev, ctx.method, ctx.args);
404             if (first == null) {
405                 first = e;
406             } else if ( prev != null ) {
407                 prev.next = e;
408             }
409             prev = e;
410
411             // See if this expression involves a VarNode. If so process the
412
// nodes involving the variable. They become the where clause of
413
// the sub select for the variable.
414
VarNode vn = extractVar(e);
415             if (vn != null) {
416                 cn = processVarNode(ctx.root, ctx.method, ctx.args, cn, vn, e);
417             } else {
418                 cn = cn.next;
419             }
420         }
421
422         // if there is now only one entry in the list then return it otherwise
423
// create a new AndExp for the list
424
if (first.next == null) {
425             return first;
426         } else {
427             return new AndExp(first);
428         }
429     }
430
431     private static VarNode extractVar(SqlExp e) {
432         if (e instanceof ExistsExp && e.childList instanceof SelectExp) {
433             return ((SelectExp) e.childList).var;
434         } else {
435             return null;
436         }
437     }
438
439     /**
440      * Process the nodes involving the variable. They become the where clause of
441      * of the sub select for the variable. This process stops as soon as a node
442      * is encountered that does not involve the variable i.e. all the variable
443      * related expressions must be together (as per spec).
444      *
445      * @return Next Node for the main loop to process
446      */

447     private Node processVarNode(SelectExp root, int method, Node args,
448             Node cn, VarNode var, SqlExp vare) {
449
450         SelectExp varSelectExp = (SelectExp)var.getStoreExtent();
451
452         // Do not use columns from the enclosing query (root) in subquery ON
453
// join conditions if the database does not allow this. If exclude is
454
// null then expressions referencing tables in the subquery and
455
// then enclosing query (root) will be left in the where clause.
456
// This is required for DB2.
457
SelectExp exclude;
458         if (root.table.sqlDriver.isSubQueryJoinMayUseOuterQueryCols()) {
459             exclude = root;
460         } else {
461             exclude = null;
462         }
463
464         // build a list of all expressions constraining the variable on first
465
SqlExp prev = null, first = null;
466         SqlExp leftSibling = vare;
467         Node ans = cn.next;
468         for (; ans != null;) {
469             SqlExp e = toSqlExp(ans, root, leftSibling, method, args);
470             if (e == null) {
471                 break;
472             }
473
474             SelectExp single = e.getSingleSelectExp(exclude);
475             if (single != null) {
476                 Join join;
477                 if (single.jdbcField != null) {
478                     join = varSelectExp.findJoinRec(single.jdbcField);
479                 } else if (vare instanceof ExistsExp) {
480                     join = ((SelectExp) vare.childList).findJoin(single);
481                 } else {
482                     join = null;
483                 }
484                 ans = ans.next;
485                 if (join != null) {
486                     join.appendJoinExp(e);
487                     continue;
488                 } else if (var.getCmd() == null) {
489                    ((SelectExp) ((ExistsExp)vare).childList).appendToWhereExp(e);
490                 }
491             } else {
492                 // recursively process nested variables
493
VarNode nested = extractVar(e);
494                 if (nested != null) {
495                     ans = processVarNode(root, method, args, ans, nested, e);
496                 } else {
497                     ans = ans.next;
498                 }
499             }
500             if (first == null) {
501                 first = e;
502             } else {
503                 prev.next = e;
504             }
505             leftSibling = e;
506             prev = e;
507         }
508
509         // attach the expression list at first to the where of the variable
510
if (first != null) varSelectExp.appendToWhereExp(first);
511
512         return ans;
513     }
514
515     public Object JavaDoc arriveOrNode(OrNode node, Object JavaDoc msg) {
516         Context ctx = (Context)msg;
517         Node childList = node.childList;
518
519         SqlExp e = processOrNodeChild(ctx.root, childList, ctx.args);
520         if (e == null) {
521             return null;
522         }
523
524         SqlExp base = e;
525         for (Node c = childList.next; c != null; c = c.next) {
526             e = e.next = processOrNodeChild(ctx.root, c, ctx.args);
527         }
528         mergeOrNodeRedundantExistsSelects(base);
529         if (base.next == null) return base;
530         return new OrExp(base);
531     }
532
533     private SqlExp processOrNodeChild(SelectExp root, Node c, Node args) {
534         Join rootJoinList = root.joinList;
535         root.joinList = null;
536         SqlExp e = toSqlExp(c, root, null, 0, args);
537         // if the child expression includes a join (e.g. field navigation)
538
// then convert it into an ExistsSelectExp
539
Join j = root.joinList;
540         if (j != null) {
541             // convert the first join into a ExistsSelectExp
542
SelectExp se = j.selectExp;
543             se.subSelectJoinExp = j.exp;
544             se.whereExp = e;
545             // make the other joins (if any) joins on this select
546
j = se.joinList;
547             if (j == null) {
548                 se.joinList = root.joinList.next;
549             } else {
550                 for (; j.next != null; j = j.next);
551                 j.next = root.joinList.next;
552             }
553             // wrap in an exists exp
554
e = new ExistsExp(se, false);
555         }
556         root.joinList = rootJoinList;
557         return e;
558     }
559
560     /**
561      * Try to merge the list of expressions starting at base. This gets rid
562      * of redundant 'exists (select ...)' sub queries.
563      */

564     private void mergeOrNodeRedundantExistsSelects(SqlExp base) {
565         for (; base != null; ) {
566             if (base instanceof ExistsExp) {
567                 SqlExp prev = base;
568                 for (SqlExp target = base.next; target != null; ) {
569                     if (mergeOrNodeRedundantExistsSelects(base, target)) {
570                         target = prev.next = target.next;
571                     } else {
572                         prev = target;
573                         target = target.next;
574                     }
575                 }
576             }
577             base = base.next;
578         }
579     }
580
581     /**
582      * Merge base and e if possible or return false. The expressions can
583      * be merged if:<p>
584      * <ol>
585      * <li>e is an ExistsExp.
586      * <li>The selectExp's have the same jdbcField.
587      * <li>The selectExp's do not have any other joins.
588      * </ol>
589      */

590     private boolean mergeOrNodeRedundantExistsSelects(SqlExp base, SqlExp e) {
591         if (!(e instanceof ExistsExp)) return false;
592         SelectExp se = (SelectExp)base.childList;
593         SelectExp ese = (SelectExp)e.childList;
594         if (se.jdbcField != ese.jdbcField) return false;
595 // if (se.joinList != null || ese.joinList != null) return false;
596
if (!Join.isEqaul(se.joinList, ese.joinList)) return false;
597         SqlExp we = se.whereExp;
598         if (we instanceof OrExp) { // extend the existing OrExp
599
SqlExp pos;
600             for (pos = we.childList; pos.next != null; pos = pos.next);
601             pos.next = ese.whereExp;
602         } else if ( se.whereExp != null ) { // create an OrExp
603
se.whereExp.next = ese.whereExp;
604             se.whereExp = new OrExp(se.whereExp);
605         }
606         // convert any references to ese into se references
607
if ( ese.whereExp != null )
608             ese.whereExp.replaceSelectExpRef(ese, se);
609         return true;
610     }
611
612     public Object JavaDoc arriveMultiplyNode(MultiplyNode node, Object JavaDoc msg) {
613         Context ctx = (Context)msg;
614         Node childList = node.childList;
615
616         SqlExp e = processMultiplyNodeChild(ctx.root, childList, null, ctx.args);
617         MultiplyExp ans = new MultiplyExp(e, node.ops);
618         for (Node c = childList.next; c != null; c = c.next) {
619             e = e.next = processMultiplyNodeChild(ctx.root, c, e, ctx.args);
620         }
621         return ans;
622     }
623
624     private SqlExp processMultiplyNodeChild(SelectExp root, Node c,
625             SqlExp leftSibling, Node args) {
626         SqlExp e = toSqlExp(c, root, leftSibling, 0, args);
627         if (e.next != null) {
628             throw BindingSupportImpl.getInstance().runtime(
629                 "Expressions consisting of multiple columns may not be used" +
630                 "with * or /");
631         }
632         return e;
633     }
634
635     public Object JavaDoc arriveAddNode(AddNode node, Object JavaDoc msg) {
636         Context ctx = (Context)msg;
637         Node childList = node.childList;
638         SqlExp e = processAddNodeChild(ctx.root, childList, null, ctx.args);
639         AddExp ans = new AddExp(e, node.ops);
640         if (node.asValue != null) ans.setExpAlias(node.asValue);
641         for (Node c = childList.next; c != null; c = c.next) {
642             e = e.next = processAddNodeChild(ctx.root, c, e, ctx.args);
643         }
644         return ans;
645     }
646
647     private SqlExp processAddNodeChild(SelectExp root, Node c, SqlExp leftSibling,
648             Node args) {
649         SqlExp e = toSqlExp(c, root, leftSibling, 0, args);
650         if (e.next != null) {
651             throw BindingSupportImpl.getInstance().runtime(
652                 "Expressions consisting of multiple columns may not be used" +
653                 "with + or -");
654         }
655         return e;
656     }
657
658     public Object JavaDoc arriveUnaryOpNode(UnaryOpNode node, Object JavaDoc msg) {
659         Context ctx = (Context)msg;
660         return new UnaryOpExp(toSqlExp(node.childList, ctx.root,
661                 ctx.leftSibling, ctx.method, ctx.args), node.op);
662     }
663
664     public Object JavaDoc arriveCompareOpNode(CompareOpNode node, Object JavaDoc msg) {
665         Context ctx = (Context)msg;
666         Node childList = node.childList;
667         SqlExp left = toSqlExp(childList, ctx.root, null, ctx.method, ctx.args);
668         SqlExp right = toSqlExp(childList.next, ctx.root, left, ctx.method, ctx.args);
669         if (left.next == null && right.next == null) {
670             int op;
671             switch (node.op) {
672                 case CompareOpNode.GT: op = BinaryOpExp.GT; break;
673                 case CompareOpNode.LT: op = BinaryOpExp.LT; break;
674                 case CompareOpNode.GE: op = BinaryOpExp.GE; break;
675                 case CompareOpNode.LE: op = BinaryOpExp.LE; break;
676                 default:
677                     throw BindingSupportImpl.getInstance().internal(
678                             "Unknown op: " + node.op);
679             }
680             return new BinaryOpExp(left, op, right);
681         }
682         throw BindingSupportImpl.getInstance().runtime(
683             "Expressions consisting of multiple columns may not be compared " +
684             "with >, <, >= or <=\n");
685     }
686
687     public Object JavaDoc arriveUnaryNode(UnaryNode node, Object JavaDoc msg) {
688         Context ctx = (Context)msg;
689         return toSqlExp(node.childList, ctx.root, ctx.leftSibling,
690                 ctx.method, ctx.args);
691     }
692
693     public Object JavaDoc arriveCastNode(CastNode node, Object JavaDoc msg) {
694         Context ctx = (Context)msg;
695         return toSqlExp(node.childList, ctx.root, ctx.leftSibling,
696                 ctx.method, ctx.args);
697     }
698
699     /**
700      * Add u to the end of the usage list for n.
701      */

702     private void addToParamNode(SqlParamUsage u, ParamNode n) {
703         if (n.usageList == null) {
704             n.usageList = u;
705         } else {
706             SqlParamUsage p = (SqlParamUsage)n.usageList;
707             for (; p.next != null; p = p.next);
708             p.next = u;
709         }
710     }
711
712     public Object JavaDoc arriveParamNode(ParamNode node, Object JavaDoc msg) {
713         Context ctx = (Context)msg;
714         SqlExp leftSibling = ctx.leftSibling;
715         SelectExp root = ctx.root;
716         Node args = ctx.args;
717
718         SqlParamUsage u = new SqlParamUsage();
719         addToParamNode(u, node);
720         if (leftSibling instanceof ColumnExp) {
721             ColumnExp left = (ColumnExp)leftSibling;
722             u.jdbcField = left.jdbcField;
723             u.col = left.col;
724             SqlExp pos = u.expList = new ParamExp(u.jdbcType, u);
725             for (;;) {
726                 if ((left = (ColumnExp)left.next) == null) break;
727                 pos = pos.next = new ParamExp(left.getJdbcType(), u);
728             }
729         } else {
730             if (leftSibling == null) {
731                 /**
732                  * Expect this to be a param collection exp
733                  * The args must be either a FieldNode of a FieldNavNode.
734                  */

735                 if (java.util.Collection JavaDoc.class.isAssignableFrom(
736                             MDStaticUtils.toSimpleClass(node.getType()))
737                         && (args instanceof FieldNode || args instanceof FieldNavNode)) {
738                     CollectionParamExp collectionParamExp =
739                         (CollectionParamExp)toSqlExp(args,
740                             root, leftSibling, MethodNode.CONTAINS_PARAM, null);
741                     u.expList = collectionParamExp;
742                     u.jdbcField = collectionParamExp.field.jdbcField;
743                     u.col = collectionParamExp.field.col;
744                     u.jdbcType = collectionParamExp.field.getJdbcType();
745                     u.javaTypeCode = collectionParamExp.field.getJavaTypeCode();
746                     u.classIndex = collectionParamExp.field.getClassIndex();
747                     return collectionParamExp;
748                 }
749                 throw BindingSupportImpl.getInstance().internal(
750                     "not implemented (leftSibling == null)");
751             }
752             if (leftSibling.next != null) {
753                 throw BindingSupportImpl.getInstance().internal(
754                     "not implemented (leftSibling.next != null)");
755             }
756             u.expList = new ParamExp(leftSibling.getJdbcType(), u);
757         }
758         if (u.jdbcField == null) {
759             u.jdbcType = leftSibling.getJdbcType();
760             u.javaTypeCode = leftSibling.getJavaTypeCode();
761             u.classIndex = leftSibling.getClassIndex();
762         }
763         return u.expList;
764     }
765
766     public Object JavaDoc arriveParamNodeProxy(ParamNodeProxy node, Object JavaDoc msg) {
767         Context ctx = (Context)msg;
768         return toSqlExp(node.getParamNode(), ctx.root, ctx.leftSibling,
769                 ctx.method, ctx.args);
770     }
771
772     public Object JavaDoc arriveVarNode(VarNode node, Object JavaDoc msg) {
773         SelectExp jdbcSelectExp = (SelectExp)node.getStoreExtent();
774         // return ColumnExp's for the primary key of our table
775
if (node.getCmd() != null) {
776             JdbcColumn[] cols = jdbcSelectExp.table.pk;
777             ColumnExp ans = new ColumnExp(cols[0], jdbcSelectExp, null);
778             SqlExp e = ans;
779             int nc = cols.length;
780             for (int i = 1; i < nc; i++) {
781                 e = e.next = new ColumnExp(cols[i], jdbcSelectExp, null);
782             }
783             return ans;
784         } else {
785             JdbcLinkCollectionField jdbcField =
786                     (JdbcLinkCollectionField)node.getFmd().storeField;
787             return new ColumnExp(jdbcField.valueColumns[0],
788                     (SelectExp)node.getFieldExtent(), null);
789         }
790     }
791
792     public Object JavaDoc arriveVarNodeProxy(VarNodeProxy node, Object JavaDoc msg) {
793         Context ctx = (Context)msg;
794         return toSqlExp(node.getVarNode(), ctx.root, ctx.leftSibling,
795                 ctx.method, ctx.args);
796     }
797
798     public Object JavaDoc arriveReservedFieldNode(ReservedFieldNode node, Object JavaDoc msg) {
799         ClassMetaData target = node.getTarget();
800         SelectExp candidateSelectExp = comp.getCandidateSelectExp();
801         JdbcColumn[] pk = ((JdbcClass)target.storeClass).table.pk;
802         ColumnExp list = new ColumnExp(pk[0], candidateSelectExp, null);
803         list.cmd = target;
804         SqlExp e = list;
805         int nc = pk.length;
806         for (int i = 1; i < nc; i++) {
807             e = e.next = new ColumnExp(pk[i], candidateSelectExp, null);
808         }
809         return list;
810     }
811
812     public Object JavaDoc arriveAggregateCountStarNode(AggregateCountStarNode node,
813             Object JavaDoc msg) {
814         return new AggregateCountStarExp(node.asValue);
815     }
816
817     public Object JavaDoc arriveAggregateNode(AggregateNode node, Object JavaDoc msg) {
818         Context ctx = (Context)msg;
819         SqlExp se = toSqlExp(node.childList, ctx.root, ctx.leftSibling,
820                 ctx.method, ctx.args);
821         String JavaDoc op;
822         switch (node.getType()) {
823             case AggregateNode.TYPE_AVG:
824                 op = "AVG";
825                 break;
826             case AggregateNode.TYPE_COUNT:
827                 op = "COUNT";
828                 break;
829             case AggregateNode.TYPE_MAX:
830                 op = "MAX";
831                 break;
832             case AggregateNode.TYPE_MIN:
833                 op = "MIN";
834                 break;
835             case AggregateNode.TYPE_SUM:
836                 op = "SUM";
837                 break;
838             default:
839                 throw BindingSupportImpl.getInstance().internal(
840                         "Uknown AggregateNode type " + node.getType());
841         };
842         return new AggregateExp(se, op, node.asValue);
843     }
844
845     public Object JavaDoc arriveAsValueNode(AsValueNode node, Object JavaDoc msg) {
846         return new ColumnExp(node.value);
847     }
848
849     public Object JavaDoc arriveGroupingNode(GroupingNode node, Object JavaDoc msg) {
850         Context ctx = (Context)msg;
851         SqlExp head = new SqlExp();
852         SqlExp current = head;
853         for (Node n = node.childList; n != null; n = n.next) {
854             if (n instanceof ReservedFieldNode) {
855                 current.next = new GroupByThisExp();
856                 current = current.next;
857             } else {
858                 current.next = toSqlExp(n, ctx.root, ctx.leftSibling,
859                         ctx.method, ctx.args);
860                 current = current.next;
861             }
862         }
863         return head.next;
864     }
865
866     public Object JavaDoc arriveResultNode(ResultNode node, Object JavaDoc msg) {
867         Context ctx = (Context)msg;
868         SqlExp head = new SqlExp();
869         SqlExp current = head;
870         for (Node n = node.childList; n != null; n = n.next) {
871             if (n instanceof ReservedFieldNode) continue;
872             current.next = toSqlExp(n, ctx.root, ctx.leftSibling, ctx.method,
873                     ctx.args);
874             current = current.next;
875         }
876         return head.next;
877     }
878
879     public Object JavaDoc arriveVarBindingNode(VarBindingNode node, Object JavaDoc msg) {
880         SelectExp se = (SelectExp)node.getVar().getStoreExtent();
881         return new ExistsExp(se, true);
882     }
883
884 }
885
886
Popular Tags