KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > EJBQLToSQL92Compiler


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins.cmp.jdbc;
23
24 import java.io.StringReader JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.Iterator JavaDoc;
32
33 import org.jboss.ejb.plugins.cmp.ejbql.*;
34 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge;
35 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge;
36 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge;
37 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
38 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCTypeMappingMetaData;
39 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationMetaData;
40 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData;
41 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData;
42 import org.jboss.ejb.EntityPersistenceStore;
43 import org.jboss.logging.Logger;
44
45 /**
46  * Compiles EJB-QL and JBossQL into SQL using OUTER and INNER joins.
47  *
48  * @author <a HREF="mailto:alex@jboss.org">Alex Loubyansky</a>
49  * @version $Revision: 58402 $
50  */

51 public final class EJBQLToSQL92Compiler
52    implements QLCompiler, JBossQLParserVisitor
53 {
54    private static final Logger log = Logger.getLogger(EJBQLToSQL92Compiler.class);
55
56    // input objects
57
private final Catalog catalog;
58    private Class JavaDoc returnType;
59    private Class JavaDoc[] parameterTypes;
60    private JDBCReadAheadMetaData readAhead;
61
62    // alias info
63
private AliasManager aliasManager;
64    private Map JavaDoc joinPaths = new HashMap JavaDoc();
65    private Map JavaDoc identifierToTable = new HashMap JavaDoc();
66    private Set JavaDoc joinedAliases = new HashSet JavaDoc();
67
68    // mapping metadata
69
private JDBCTypeMappingMetaData typeMapping;
70    private JDBCTypeFactory typeFactory;
71
72    // output objects
73
private boolean forceDistinct;
74    private String JavaDoc sql;
75    private int offsetParam;
76    private int offsetValue;
77    private int limitParam;
78    private int limitValue;
79    private JDBCEntityPersistenceStore selectManager;
80    private Object JavaDoc selectObject;
81    private List JavaDoc inputParameters = new ArrayList JavaDoc();
82
83    private List JavaDoc leftJoinCMRList = new ArrayList JavaDoc();
84    private StringBuffer JavaDoc onFindCMRJoin;
85
86    private boolean countCompositePk;
87    private boolean selectDistinct;
88
89    public EJBQLToSQL92Compiler(Catalog catalog)
90    {
91       this.catalog = catalog;
92    }
93
94    public void compileEJBQL(String JavaDoc ejbql, Class JavaDoc returnType, Class JavaDoc[] parameterTypes, JDBCQueryMetaData metadata)
95       throws Exception JavaDoc
96    {
97       // reset all state variables
98
reset();
99
100       // set input arguemts
101
this.returnType = returnType;
102       this.parameterTypes = parameterTypes;
103       this.readAhead = metadata.getReadAhead();
104
105       // get the parser
106
EJBQLParser parser = new EJBQLParser(new StringReader JavaDoc(""));
107
108       try
109       {
110          // parse the ejbql into an abstract sytax tree
111
ASTEJBQL ejbqlNode = parser.parse(catalog, parameterTypes, ejbql);
112
113          // translate to sql
114
sql = ejbqlNode.jjtAccept(this, new StringBuffer JavaDoc()).toString();
115       }
116       catch(Exception JavaDoc e)
117       {
118          // if there is a problem reset the state before exiting
119
reset();
120          throw e;
121       }
122       catch(Error JavaDoc e)
123       {
124          // lame javacc lexer throws Errors
125
reset();
126          throw e;
127       }
128    }
129
130    public void compileJBossQL(String JavaDoc ejbql, Class JavaDoc returnType, Class JavaDoc[] parameterTypes, JDBCQueryMetaData metadata)
131       throws Exception JavaDoc
132    {
133       // reset all state variables
134
reset();
135
136       // set input arguemts
137
this.returnType = returnType;
138       this.parameterTypes = parameterTypes;
139       this.readAhead = metadata.getReadAhead();
140
141       // get the parser
142
JBossQLParser parser = new JBossQLParser(new StringReader JavaDoc(""));
143
144       try
145       {
146          // parse the ejbql into an abstract sytax tree
147
ASTEJBQL ejbqlNode = parser.parse(catalog, parameterTypes, ejbql);
148
149          // translate to sql
150
sql = ejbqlNode.jjtAccept(this, new StringBuffer JavaDoc()).toString();
151
152          if(log.isTraceEnabled())
153          {
154             log.trace("ejbql: " + ejbql);
155             log.trace("sql: " + sql);
156          }
157       }
158       catch(Exception JavaDoc e)
159       {
160          // if there is a problem reset the state before exiting
161
reset();
162          throw e;
163       }
164       catch(Error JavaDoc e)
165       {
166          // lame javacc lexer throws Errors
167
reset();
168          throw e;
169       }
170    }
171
172    public String JavaDoc getSQL()
173    {
174       return sql;
175    }
176
177    public int getOffsetValue()
178    {
179       return offsetValue;
180    }
181
182    public int getOffsetParam()
183    {
184       return offsetParam;
185    }
186
187    public int getLimitValue()
188    {
189       return limitValue;
190    }
191
192    public int getLimitParam()
193    {
194       return limitParam;
195    }
196
197    public boolean isSelectEntity()
198    {
199       return selectObject instanceof JDBCAbstractEntityBridge;
200    }
201
202    public JDBCAbstractEntityBridge getSelectEntity()
203    {
204       return (JDBCAbstractEntityBridge) selectObject;
205    }
206
207    public boolean isSelectField()
208    {
209       boolean result;
210       if(selectObject instanceof JDBCFieldBridge)
211       {
212          JDBCFieldBridge field = (JDBCFieldBridge) selectObject;
213          result = field.isCMPField();
214       }
215       else
216       {
217          result = false;
218       }
219       return result;
220    }
221
222    public JDBCFieldBridge getSelectField()
223    {
224       return (JDBCFieldBridge) selectObject;
225    }
226
227    public SelectFunction getSelectFunction()
228    {
229       return (SelectFunction) selectObject;
230    }
231
232    public EntityPersistenceStore getStoreManager()
233    {
234       return selectManager;
235    }
236
237    public List JavaDoc getInputParameters()
238    {
239       return inputParameters;
240    }
241
242    public List JavaDoc getLeftJoinCMRList()
243    {
244       return leftJoinCMRList;
245    }
246
247    public boolean isSelectDistinct()
248    {
249       return selectDistinct;
250    }
251
252    public Object JavaDoc visit(SimpleNode node, Object JavaDoc data)
253    {
254       throw new RuntimeException JavaDoc("Internal error: Found unknown node type in " +
255          "EJB-QL abstract syntax tree: node=" + node);
256    }
257
258    public Object JavaDoc visit(ASTEJBQL node, Object JavaDoc data)
259    {
260       Node selectNode = node.jjtGetChild(0);
261       Node fromNode = node.jjtGetChild(1);
262
263       // compile selectNode
264
StringBuffer JavaDoc selectClause = new StringBuffer JavaDoc(50);
265       selectNode.jjtAccept(this, selectClause);
266
267       StringBuffer JavaDoc whereClause = null;
268       StringBuffer JavaDoc orderByClause = null;
269       for(int i = 2; i < node.jjtGetNumChildren(); ++i)
270       {
271          Node childNode = node.jjtGetChild(i);
272          if(childNode instanceof ASTWhere)
273          {
274             whereClause = new StringBuffer JavaDoc(20);
275             childNode.jjtAccept(this, whereClause);
276          }
277          else if(childNode instanceof ASTOrderBy)
278          {
279             orderByClause = new StringBuffer JavaDoc();
280             childNode.jjtAccept(this, orderByClause);
281          }
282          else if(childNode instanceof ASTLimitOffset)
283          {
284             childNode.jjtAccept(this, null);
285          }
286       }
287
288       // compile fromNode
289
StringBuffer JavaDoc fromClause = new StringBuffer JavaDoc(30);
290       fromNode.jjtAccept(this, fromClause);
291
292       // left-join
293
for(Iterator JavaDoc iter = identifierToTable.entrySet().iterator(); iter.hasNext();)
294       {
295          final Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
296          final String JavaDoc identifier = (String JavaDoc) entry.getKey();
297          final String JavaDoc table = (String JavaDoc) entry.getValue();
298          final String JavaDoc alias = aliasManager.getAlias(identifier);
299
300          fromClause.append(table).append(' ').append(alias);
301          join(alias, fromClause);
302
303          if(iter.hasNext())
304          {
305             fromClause.append(SQLUtil.COMMA);
306          }
307       }
308
309       selectDistinct = ((ASTSelect) selectNode).distinct || returnType == Set JavaDoc.class || forceDistinct;
310
311       // assemble sql
312
StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
313       if(selectManager.getMetaData().hasRowLocking() && !(selectObject instanceof SelectFunction))
314       {
315          JDBCFunctionMappingMetaData rowLockingTemplate = typeMapping.getRowLockingTemplate();
316          if(rowLockingTemplate == null)
317          {
318             throw new IllegalStateException JavaDoc("Row locking template is not defined for given mapping: " + typeMapping.getName());
319          }
320
321          boolean distinct = selectDistinct;
322
323          Object JavaDoc args[] = new Object JavaDoc[]{
324             distinct ? SQLUtil.DISTINCT + selectClause : selectClause.toString(),
325             fromClause,
326             whereClause == null || whereClause.length() == 0 ? null : whereClause,
327             orderByClause == null || orderByClause.length() == 0 ? null : orderByClause
328          };
329          rowLockingTemplate.getFunctionSql(args, sql);
330       }
331       else
332       {
333          sql.append(SQLUtil.SELECT);
334          if(selectDistinct)
335          {
336             sql.append(SQLUtil.DISTINCT);
337          }
338          sql.append(selectClause)
339             .append(SQLUtil.FROM)
340             .append(fromClause);
341
342          if(whereClause != null && whereClause.length() > 0)
343          {
344             sql.append(SQLUtil.WHERE).append(whereClause);
345          }
346
347          if(orderByClause != null && orderByClause.length() > 0)
348          {
349             sql.append(SQLUtil.ORDERBY).append(orderByClause);
350          }
351       }
352
353       if(countCompositePk)
354       {
355          sql.insert(0, "SELECT COUNT(*) FROM (").append(") t_count");
356       }
357
358       return data;
359    }
360
361    public Object JavaDoc visit(ASTOrderBy node, Object JavaDoc data)
362    {
363       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
364       node.jjtGetChild(0).jjtAccept(this, data);
365       for(int i = 1; i < node.jjtGetNumChildren(); i++)
366       {
367          buf.append(SQLUtil.COMMA);
368          node.jjtGetChild(i).jjtAccept(this, data);
369       }
370       return data;
371    }
372
373    public Object JavaDoc visit(ASTOrderByPath node, Object JavaDoc data)
374    {
375       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
376       node.jjtGetChild(0).jjtAccept(this, data);
377       if(node.ascending)
378       {
379          buf.append(SQLUtil.ASC);
380       }
381       else
382       {
383          buf.append(SQLUtil.DESC);
384       }
385       return data;
386    }
387
388    public Object JavaDoc visit(ASTLimitOffset node, Object JavaDoc data)
389    {
390       int child = 0;
391       if(node.hasOffset)
392       {
393          Node offsetNode = node.jjtGetChild(child++);
394          if(offsetNode instanceof ASTParameter)
395          {
396             ASTParameter param = (ASTParameter) offsetNode;
397             Class JavaDoc parameterType = getParameterType(param.number);
398             if(int.class != parameterType && Integer JavaDoc.class != parameterType)
399             {
400                throw new IllegalStateException JavaDoc("OFFSET parameter must be an int");
401             }
402             offsetParam = param.number;
403          }
404          else
405          {
406             ASTExactNumericLiteral param = (ASTExactNumericLiteral) offsetNode;
407             offsetValue = (int) param.value;
408          }
409       }
410
411       if(node.hasLimit)
412       {
413          Node limitNode = node.jjtGetChild(child);
414          if(limitNode instanceof ASTParameter)
415          {
416             ASTParameter param = (ASTParameter) limitNode;
417             Class JavaDoc parameterType = getParameterType(param.number);
418             if(int.class != parameterType && Integer JavaDoc.class != parameterType)
419             {
420                throw new IllegalStateException JavaDoc("LIMIT parameter must be an int");
421             }
422             limitParam = param.number;
423          }
424          else
425          {
426             ASTExactNumericLiteral param = (ASTExactNumericLiteral) limitNode;
427             limitValue = (int) param.value;
428          }
429       }
430       return data;
431    }
432
433    public Object JavaDoc visit(ASTSelect select, Object JavaDoc data)
434    {
435       StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
436
437       final Node child0 = select.jjtGetChild(0);
438       final ASTPath path;
439       if(child0 instanceof ASTPath)
440       {
441          path = (ASTPath) child0;
442
443          if(path.isCMPField())
444          {
445             // set the select object
446
JDBCFieldBridge selectField = (JDBCFieldBridge) path.getCMPField();
447             selectManager = selectField.getManager();
448             selectObject = selectField;
449             setTypeFactory(selectManager.getJDBCTypeFactory());
450
451             // todo inner or left?
452
//addLeftJoinPath(path);
453
addInnerJoinPath(path);
454
455             String JavaDoc alias = aliasManager.getAlias(path.getPath(path.size() - 2));
456             SQLUtil.getColumnNamesClause(selectField, alias, sql);
457          }
458          else
459          {
460             JDBCAbstractEntityBridge selectEntity = (JDBCAbstractEntityBridge) path.getEntity();
461             selectManager = selectEntity.getManager();
462             selectObject = selectEntity;
463             setTypeFactory(selectEntity.getManager().getJDBCTypeFactory());
464
465             final String JavaDoc alias = aliasManager.getAlias(path.getPath());
466             if(select.distinct)
467             {
468                SQLUtil.getSearchableColumnNamesClause(selectEntity.getTableFields(), alias, sql);
469             }
470             else
471             {
472                SQLUtil.getColumnNamesClause(selectEntity.getTableFields(), alias, sql);
473             }
474
475             /*
476             if(readAhead.isOnFind())
477             {
478                String eagerLoadGroupName = readAhead.getEagerLoadGroup();
479                boolean[] loadGroupMask = selectEntity.getLoadGroupMask(eagerLoadGroupName);
480                SQLUtil.appendColumnNamesClause(
481                   selectEntity.getTableFields(),
482                   loadGroupMask,
483                   alias,
484                   sql
485                );
486             }
487             */

488
489             addLeftJoinPath(path);
490          }
491       }
492       else
493       {
494          // the function should take a path expresion as a parameter
495
path = getPathFromChildren(child0);
496
497          if(path == null)
498          {
499             throw new IllegalStateException JavaDoc("The function in SELECT clause does not contain a path expression.");
500          }
501
502          if(path.isCMPField())
503          {
504             JDBCFieldBridge selectField = (JDBCFieldBridge) path.getCMPField();
505             selectManager = selectField.getManager();
506             setTypeFactory(selectManager.getJDBCTypeFactory());
507          }
508          else if(path.isCMRField())
509          {
510             JDBCFieldBridge cmrField = (JDBCFieldBridge) path.getCMRField();
511             selectManager = cmrField.getManager();
512             setTypeFactory(selectManager.getJDBCTypeFactory());
513             addLeftJoinPath(path);
514          }
515          else
516          {
517             final JDBCAbstractEntityBridge entity = (JDBCAbstractEntityBridge) path.getEntity();
518             selectManager = entity.getManager();
519             setTypeFactory(selectManager.getJDBCTypeFactory());
520             addLeftJoinPath(path);
521          }
522
523          selectObject = child0;
524          child0.jjtAccept(this, data);
525       }
526
527       return data;
528    }
529
530    public Object JavaDoc visit(ASTWhere node, Object JavaDoc data)
531    {
532       node.jjtGetChild(0).jjtAccept(this, data);
533       return data;
534    }
535
536    public Object JavaDoc visit(ASTOr node, Object JavaDoc data)
537    {
538       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
539       node.jjtGetChild(0).jjtAccept(this, data);
540       for(int i = 1; i < node.jjtGetNumChildren(); ++i)
541       {
542          buf.append(SQLUtil.OR);
543          node.jjtGetChild(i).jjtAccept(this, data);
544       }
545       return data;
546    }
547
548    public Object JavaDoc visit(ASTWhereConditionalTerm node, Object JavaDoc data)
549    {
550       for(int i = 0; i < node.jjtGetNumChildren(); ++i)
551       {
552          node.jjtGetChild(i).jjtAccept(this, data);
553       }
554       return data;
555    }
556
557    public Object JavaDoc visit(ASTAnd node, Object JavaDoc data)
558    {
559       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
560       node.jjtGetChild(0).jjtAccept(this, data);
561       for(int i = 1; i < node.jjtGetNumChildren(); i++)
562       {
563          buf.append(SQLUtil.AND);
564          node.jjtGetChild(i).jjtAccept(this, data);
565       }
566       return data;
567    }
568
569    public Object JavaDoc visit(ASTNot node, Object JavaDoc data)
570    {
571       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
572       buf.append(SQLUtil.NOT);
573       node.jjtGetChild(0).jjtAccept(this, data);
574       return data;
575    }
576
577    public Object JavaDoc visit(ASTConditionalParenthetical node, Object JavaDoc data)
578    {
579       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
580       buf.append('(');
581       node.jjtGetChild(0).jjtAccept(this, data);
582       buf.append(')');
583       return data;
584    }
585
586    public Object JavaDoc visit(ASTBetween node, Object JavaDoc data)
587    {
588       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
589       node.jjtGetChild(0).jjtAccept(this, data);
590       if(node.not)
591       {
592          buf.append(SQLUtil.NOT);
593       }
594       buf.append(SQLUtil.BETWEEN);
595       node.jjtGetChild(1).jjtAccept(this, data);
596       buf.append(SQLUtil.AND);
597       node.jjtGetChild(2).jjtAccept(this, data);
598       return data;
599    }
600
601    public Object JavaDoc visit(ASTIn node, Object JavaDoc data)
602    {
603       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
604       node.jjtGetChild(0).jjtAccept(this, data);
605       if(node.not)
606       {
607          buf.append(SQLUtil.NOT);
608       }
609       buf.append(SQLUtil.IN).append('(');
610       node.jjtGetChild(1).jjtAccept(this, data);
611       for(int i = 2; i < node.jjtGetNumChildren(); i++)
612       {
613          buf.append(SQLUtil.COMMA);
614          node.jjtGetChild(i).jjtAccept(this, data);
615       }
616       buf.append(')');
617       return data;
618    }
619
620    public Object JavaDoc visit(ASTLike node, Object JavaDoc data)
621    {
622       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
623       node.jjtGetChild(0).jjtAccept(this, data);
624       if(node.not)
625       {
626          buf.append(SQLUtil.NOT);
627       }
628       buf.append(SQLUtil.LIKE);
629       node.jjtGetChild(1).jjtAccept(this, data);
630       if(node.jjtGetNumChildren() == 3)
631       {
632          buf.append(SQLUtil.ESCAPE);
633          node.jjtGetChild(2).jjtAccept(this, data);
634       }
635       return data;
636    }
637
638    public Object JavaDoc visit(ASTNullComparison node, Object JavaDoc data)
639    {
640       StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
641
642       final Node child0 = node.jjtGetChild(0);
643       if(child0 instanceof ASTPath)
644       {
645          ASTPath path = (ASTPath) child0;
646          addLeftJoinPath(path);
647
648          JDBCFieldBridge field = (JDBCFieldBridge) path.getField();
649
650          if(field instanceof JDBCAbstractCMRFieldBridge)
651          {
652             JDBCAbstractCMRFieldBridge cmrField = (JDBCAbstractCMRFieldBridge)field;
653             final String JavaDoc alias;
654             final JDBCFieldBridge[] keyFields;
655
656             if(cmrField.hasForeignKey())
657             {
658                alias = aliasManager.getAlias(path.getPath(path.size() - 2));
659                keyFields = cmrField.getForeignKeyFields();
660             }
661             else
662             {
663                alias = aliasManager.getAlias(path.getPath());
664                if(cmrField.getMetaData().getRelationMetaData().isTableMappingStyle())
665                {
666                   keyFields = cmrField.getRelatedCMRField().getEntity().getPrimaryKeyFields();
667                }
668                else
669                {
670                   keyFields = cmrField.getRelatedCMRField().getForeignKeyFields();
671                }
672             }
673
674             SQLUtil.getIsNullClause(node.not, keyFields, alias, sql);
675          }
676          else
677          {
678             String JavaDoc alias = aliasManager.getAlias(path.getPath(path.size() - 2));
679             SQLUtil.getIsNullClause(node.not, field, alias, sql);
680          }
681       }
682       else if(child0 instanceof ASTParameter)
683       {
684          ASTParameter param = (ASTParameter) child0;
685          Class JavaDoc type = getParameterType(param.number);
686
687          QueryParameter queryParam = new QueryParameter(param.number - 1, typeFactory.getJDBCType(type));
688          inputParameters.add(queryParam);
689
690          sql.append("? IS ");
691          if(node.not)
692          {
693             sql.append(SQLUtil.NOT);
694          }
695          sql.append(SQLUtil.NULL);
696       }
697       else
698       {
699          throw new IllegalStateException JavaDoc("Unexpected node in IS NULL clause: " + node);
700       }
701
702       return data;
703    }
704
705    public Object JavaDoc visit(ASTIsEmpty node, Object JavaDoc data)
706    {
707       ASTPath path = (ASTPath) node.jjtGetChild(0);
708       if(!path.isCMRField())
709       {
710          throw new IllegalStateException JavaDoc("IS EMPTY can be applied only to collection valued CMR field.");
711       }
712
713       addLeftJoinPath(path);
714
715       StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
716       JDBCAbstractCMRFieldBridge cmrField = (JDBCAbstractCMRFieldBridge) path.getCMRField();
717       JDBCAbstractEntityBridge relatedEntity = (JDBCAbstractEntityBridge) cmrField.getRelatedEntity();
718       String JavaDoc alias = aliasManager.getAlias(path.getPath());
719       SQLUtil.getIsNullClause(node.not, relatedEntity.getPrimaryKeyFields(), alias, sql);
720
721       return data;
722    }
723
724    public Object JavaDoc visit(ASTMemberOf node, Object JavaDoc data)
725    {
726       Node member = node.jjtGetChild(0);
727       ASTPath colPath = (ASTPath) node.jjtGetChild(1);
728       JDBCAbstractEntityBridge colEntity = (JDBCAbstractEntityBridge) colPath.getEntity();
729
730       StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
731
732       if(node.not)
733       {
734          sql.append(SQLUtil.NOT);
735       }
736
737       sql.append(SQLUtil.EXISTS).append('(').append(SQLUtil.SELECT);
738
739       if(member instanceof ASTParameter)
740       {
741          ASTParameter toParam = (ASTParameter) member;
742          verifyParameterEntityType(toParam.number, colEntity);
743          inputParameters.addAll(QueryParameter.createParameters(toParam.number - 1, colEntity));
744
745          String JavaDoc parentAlias = aliasManager.getAlias(colPath.getPath(0));
746          String JavaDoc localParentAlias = aliasManager.getAlias(colPath.getPath(0) + "_local");
747          JDBCAbstractEntityBridge parentEntity = (JDBCAbstractEntityBridge) colPath.getEntity(0);
748          SQLUtil.getColumnNamesClause(parentEntity.getPrimaryKeyFields(), localParentAlias, sql);
749          sql.append(SQLUtil.FROM)
750             .append(parentEntity.getQualifiedTableName()).append(' ').append(localParentAlias);
751          innerJoinPath(colPath, sql);
752
753          sql.append(SQLUtil.WHERE);
754
755          JDBCAbstractEntityBridge col0 = (JDBCAbstractEntityBridge)colPath.getEntity(0);
756          SQLUtil.getSelfCompareWhereClause(col0.getPrimaryKeyFields(), parentAlias, localParentAlias, sql);
757          sql.append(SQLUtil.AND);
758
759          String JavaDoc localColAlias = aliasManager.getAlias(colPath.getPath() + "_local");
760          SQLUtil.getWhereClause(colEntity.getPrimaryKeyFields(), localColAlias, sql);
761       }
762       else
763       {
764          ASTPath memberPath = (ASTPath) member;
765          JDBCAbstractEntityBridge memberEntity = (JDBCAbstractEntityBridge) memberPath.getEntity();
766
767          if(!memberEntity.equals(colEntity))
768          {
769             throw new IllegalStateException JavaDoc("Member must be if the same type as the collection, got: member="
770                +
771                memberEntity.getEntityName()
772                + ", collection=" + colEntity.getEntityName());
773          }
774
775          String JavaDoc memberAlias = aliasManager.getAlias(memberPath.getPath());
776
777          if(memberPath.size() > 1)
778          {
779             String JavaDoc parentAlias = aliasManager.getAlias(memberPath.getPath(0) + "_local");
780             JDBCAbstractEntityBridge parentEntity = (JDBCAbstractEntityBridge) memberPath.getEntity(0);
781             SQLUtil.getColumnNamesClause(parentEntity.getPrimaryKeyFields(), parentAlias, sql);
782             sql.append(SQLUtil.FROM)
783                .append(parentEntity.getQualifiedTableName()).append(' ').append(parentAlias);
784             innerJoinPath(memberPath, sql);
785             innerJoinPath(colPath, sql);
786          }
787          else if(colPath.size() > 1)
788          {
789             String JavaDoc parentAlias = aliasManager.getAlias(colPath.getPath(0) + "_local");
790             JDBCAbstractEntityBridge parentEntity = (JDBCAbstractEntityBridge) colPath.getEntity(0);
791             SQLUtil.getColumnNamesClause(parentEntity.getPrimaryKeyFields(), parentAlias, sql);
792             sql.append(SQLUtil.FROM)
793                .append(parentEntity.getQualifiedTableName()).append(' ').append(parentAlias);
794             innerJoinPath(colPath, sql);
795          }
796          else
797          {
798             throw new IllegalStateException JavaDoc(
799                "There should be collection valued path expression, not identification variable.");
800          }
801
802          sql.append(SQLUtil.WHERE);
803
804          JDBCAbstractEntityBridge member0 = (JDBCAbstractEntityBridge)memberPath.getEntity(0);
805          String JavaDoc colAliasLocal = aliasManager.getAlias(colPath.getPath() + "_local");
806          if(memberPath.size() > 1)
807          {
808             String JavaDoc memberAliasLocal = aliasManager.getAlias(memberPath.getPath() + "_local");
809             SQLUtil.getSelfCompareWhereClause(colEntity.getPrimaryKeyFields(),
810                memberAliasLocal,
811                colAliasLocal,
812                sql);
813
814             sql.append(SQLUtil.AND);
815
816             String JavaDoc member0Alias = aliasManager.getAlias(memberPath.getPath(0));
817             String JavaDoc member0AliasLocal = aliasManager.getAlias(memberPath.getPath(0) + "_local");
818             SQLUtil.getSelfCompareWhereClause(member0.getPrimaryKeyFields(),
819                member0Alias,
820                member0AliasLocal,
821                sql);
822          }
823          else
824          {
825             SQLUtil.getSelfCompareWhereClause(member0.getPrimaryKeyFields(), memberAlias, colAliasLocal, sql);
826          }
827       }
828
829       sql.append(')');
830
831       return data;
832    }
833
834    private void innerJoinPath(ASTPath path, StringBuffer JavaDoc sql)
835    {
836       if(path.size() < 2)
837       {
838          return;
839       }
840
841       String JavaDoc parentAlias = aliasManager.getAlias(path.getPath(0) + "_local");
842       String JavaDoc leftAlias = parentAlias;
843       for(int i = 1; i < path.size(); ++i)
844       {
845          String JavaDoc curPath = path.getPath(i);
846          final String JavaDoc joinAlias = aliasManager.getAlias(curPath + "_local");
847
848          final JDBCAbstractCMRFieldBridge cmrField = (JDBCAbstractCMRFieldBridge) path.getCMRField(i);
849          final JDBCAbstractEntityBridge joinEntity = (JDBCAbstractEntityBridge) cmrField.getRelatedEntity();
850
851          JDBCRelationMetaData relation = cmrField.getMetaData().getRelationMetaData();
852
853          String JavaDoc join = " INNER JOIN ";
854
855          if(relation.isTableMappingStyle())
856          {
857             String JavaDoc relTableAlias = aliasManager.getRelationTableAlias(curPath + "_local");
858             sql.append(join)
859                .append(cmrField.getQualifiedTableName())
860                .append(' ')
861                .append(relTableAlias)
862                .append(" ON ");
863             SQLUtil.getRelationTableJoinClause(cmrField, leftAlias, relTableAlias, sql);
864
865             sql.append(join)
866                .append(joinEntity.getQualifiedTableName())
867                .append(' ')
868                .append(joinAlias)
869                .append(" ON ");
870             SQLUtil.getRelationTableJoinClause(cmrField.getRelatedCMRField(), joinAlias, relTableAlias, sql);
871          }
872          else
873          {
874             sql.append(join)
875                .append(joinEntity.getQualifiedTableName())
876                .append(' ')
877                .append(joinAlias)
878                .append(" ON ");
879
880             SQLUtil.getJoinClause(cmrField, leftAlias, joinAlias, sql);
881          }
882
883          leftAlias = joinAlias;
884       }
885    }
886
887    public Object JavaDoc visit(ASTStringComparison node, Object JavaDoc data)
888    {
889       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
890       node.jjtGetChild(0).jjtAccept(this, data);
891       buf.append(' ').append(node.opp).append(' ');
892       node.jjtGetChild(1).jjtAccept(this, data);
893       return data;
894    }
895
896    public Object JavaDoc visit(ASTBooleanComparison node, Object JavaDoc data)
897    {
898       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
899       node.jjtGetChild(0).jjtAccept(this, data);
900       if(node.jjtGetNumChildren() == 2)
901       {
902          buf.append(' ').append(node.opp).append(' ');
903          node.jjtGetChild(1).jjtAccept(this, data);
904       }
905       return data;
906    }
907
908    public Object JavaDoc visit(ASTDatetimeComparison node, Object JavaDoc data)
909    {
910       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
911       node.jjtGetChild(0).jjtAccept(this, data);
912       buf.append(' ').append(node.opp).append(' ');
913       node.jjtGetChild(1).jjtAccept(this, data);
914       return data;
915    }
916
917    public Object JavaDoc visit(ASTValueClassComparison node, Object JavaDoc data)
918    {
919       throw new IllegalStateException JavaDoc("Value class comparison is not yet supported.");
920    }
921
922    public Object JavaDoc visit(ASTEntityComparison node, Object JavaDoc data)
923    {
924       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
925       Node arg0 = node.jjtGetChild(0);
926       Node arg1 = node.jjtGetChild(1);
927       if(node.opp.equals(SQLUtil.NOT_EQUAL))
928       {
929          compareEntity(true, arg0, arg1, buf);
930       }
931       else
932       {
933          compareEntity(false, arg0, arg1, buf);
934       }
935       return data;
936    }
937
938    public Object JavaDoc visit(ASTArithmeticComparison node, Object JavaDoc data)
939    {
940       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
941       node.jjtGetChild(0).jjtAccept(this, data);
942       buf.append(' ').append(node.opp).append(' ');
943       node.jjtGetChild(1).jjtAccept(this, data);
944       return data;
945    }
946
947    public Object JavaDoc visit(ASTPlusMinus node, Object JavaDoc data)
948    {
949       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
950       node.jjtGetChild(0).jjtAccept(this, data);
951       for(int i = 1; i < node.jjtGetNumChildren(); i++)
952       {
953          buf.append(' ').append(node.opps.get(i - 1)).append(' ');
954          node.jjtGetChild(i).jjtAccept(this, data);
955       }
956       return data;
957    }
958
959    public Object JavaDoc visit(ASTMultDiv node, Object JavaDoc data)
960    {
961       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
962       node.jjtGetChild(0).jjtAccept(this, data);
963       for(int i = 1; i < node.jjtGetNumChildren(); i++)
964       {
965          buf.append(' ').append(node.opps.get(i - 1)).append(' ');
966          node.jjtGetChild(i).jjtAccept(this, data);
967       }
968       return data;
969    }
970
971    public Object JavaDoc visit(ASTNegation node, Object JavaDoc data)
972    {
973       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
974       buf.append('-');
975       node.jjtGetChild(0).jjtAccept(this, data);
976       return data;
977    }
978
979    public Object JavaDoc visit(ASTArithmeticParenthetical node, Object JavaDoc data)
980    {
981       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
982       buf.append('(');
983       node.jjtGetChild(0).jjtAccept(this, data);
984       buf.append(')');
985       return data;
986    }
987
988    public Object JavaDoc visit(ASTStringParenthetical node, Object JavaDoc data)
989    {
990       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
991       buf.append('(');
992       node.jjtGetChild(0).jjtAccept(this, data);
993       buf.append(')');
994       return data;
995    }
996
997    public Object JavaDoc visit(ASTConcat node, Object JavaDoc data)
998    {
999       StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1000      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.CONCAT);
1001      Object JavaDoc[] args = childrenToStringArr(2, node);
1002      function.getFunctionSql(args, buf);
1003      return data;
1004   }
1005
1006   public Object JavaDoc visit(ASTSubstring node, Object JavaDoc data)
1007   {
1008      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1009      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.SUBSTRING);
1010      Object JavaDoc[] args = childrenToStringArr(3, node);
1011      function.getFunctionSql(args, buf);
1012      return data;
1013   }
1014
1015   public Object JavaDoc visit(ASTUCase node, Object JavaDoc data)
1016   {
1017      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1018      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.UCASE);
1019      Object JavaDoc[] args = childrenToStringArr(1, node);
1020      function.getFunctionSql(args, buf);
1021      return data;
1022   }
1023
1024   public Object JavaDoc visit(ASTLCase node, Object JavaDoc data)
1025   {
1026      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1027      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LCASE);
1028      Object JavaDoc[] args = childrenToStringArr(1, node);
1029      function.getFunctionSql(args, buf);
1030      return data;
1031   }
1032
1033   public Object JavaDoc visit(ASTLength node, Object JavaDoc data)
1034   {
1035      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1036      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LENGTH);
1037      Object JavaDoc[] args = childrenToStringArr(1, node);
1038      function.getFunctionSql(args, buf);
1039      return data;
1040   }
1041
1042   public Object JavaDoc visit(ASTLocate node, Object JavaDoc data)
1043   {
1044      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1045      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.LOCATE);
1046      Object JavaDoc[] args = new Object JavaDoc[3];
1047      args[0] = node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString();
1048      args[1] = node.jjtGetChild(1).jjtAccept(this, new StringBuffer JavaDoc()).toString();
1049      if(node.jjtGetNumChildren() == 3)
1050      {
1051         args[2] = node.jjtGetChild(2).jjtAccept(this, new StringBuffer JavaDoc()).toString();
1052      }
1053      else
1054      {
1055         args[2] = "1";
1056      }
1057      function.getFunctionSql(args, buf);
1058      return data;
1059   }
1060
1061   public Object JavaDoc visit(ASTAbs node, Object JavaDoc data)
1062   {
1063      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1064      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.ABS);
1065      Object JavaDoc[] args = childrenToStringArr(1, node);
1066      function.getFunctionSql(args, buf);
1067      return data;
1068   }
1069
1070   public Object JavaDoc visit(ASTSqrt node, Object JavaDoc data)
1071   {
1072      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1073      JDBCFunctionMappingMetaData function = typeMapping.getFunctionMapping(JDBCTypeMappingMetaData.SQRT);
1074      Object JavaDoc[] args = childrenToStringArr(1, node);
1075      function.getFunctionSql(args, buf);
1076      return data;
1077   }
1078
1079   public Object JavaDoc visit(ASTMod node, Object JavaDoc data)
1080   {
1081      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1082      JDBCFunctionMappingMetaData function = JDBCTypeMappingMetaData.MOD_FUNC;
1083      Object JavaDoc[] args = childrenToStringArr(2, node);
1084      function.getFunctionSql(args, buf);
1085      return data;
1086   }
1087
1088   public Object JavaDoc visit(ASTAvg node, Object JavaDoc data)
1089   {
1090      node.setResultType(returnType);
1091      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1092      Object JavaDoc[] args = new Object JavaDoc[]{
1093         node.distinct,
1094         node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString(),
1095      };
1096      JDBCTypeMappingMetaData.AVG_FUNC.getFunctionSql(args, buf);
1097      return data;
1098   }
1099
1100   public Object JavaDoc visit(ASTMax node, Object JavaDoc data)
1101   {
1102      node.setResultType(returnType);
1103      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1104      Object JavaDoc[] args = new Object JavaDoc[]{
1105         node.distinct,
1106         node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString(),
1107      };
1108      JDBCTypeMappingMetaData.MAX_FUNC.getFunctionSql(args, buf);
1109      return data;
1110   }
1111
1112   public Object JavaDoc visit(ASTMin node, Object JavaDoc data)
1113   {
1114      node.setResultType(returnType);
1115      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1116      Object JavaDoc[] args = new Object JavaDoc[]{
1117         node.distinct,
1118         node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString(),
1119      };
1120      JDBCTypeMappingMetaData.MIN_FUNC.getFunctionSql(args, buf);
1121      return data;
1122   }
1123
1124   public Object JavaDoc visit(ASTSum node, Object JavaDoc data)
1125   {
1126      node.setResultType(returnType);
1127      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1128      Object JavaDoc[] args = new Object JavaDoc[]{
1129         node.distinct,
1130         node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString(),
1131      };
1132      JDBCTypeMappingMetaData.SUM_FUNC.getFunctionSql(args, buf);
1133      return data;
1134   }
1135
1136   public Object JavaDoc visit(ASTCount node, Object JavaDoc data)
1137   {
1138      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1139      node.setResultType(returnType);
1140
1141      Object JavaDoc args[];
1142      final ASTPath cntPath = (ASTPath) node.jjtGetChild(0);
1143      if(cntPath.isCMPField())
1144      {
1145         args = new Object JavaDoc[]{node.distinct, node.jjtGetChild(0).jjtAccept(this, new StringBuffer JavaDoc()).toString()};
1146      }
1147      else
1148      {
1149         JDBCAbstractEntityBridge entity = (JDBCAbstractEntityBridge) cntPath.getEntity();
1150         final JDBCFieldBridge[] pkFields = entity.getPrimaryKeyFields();
1151         if(pkFields.length > 1)
1152         {
1153            countCompositePk = true;
1154            forceDistinct = node.distinct.length() > 0;
1155
1156            addLeftJoinPath(cntPath);
1157
1158            String JavaDoc alias = aliasManager.getAlias(cntPath.getPath());
1159            SQLUtil.getColumnNamesClause(entity.getPrimaryKeyFields(),
1160               alias,
1161               buf);
1162
1163            return buf;
1164         }
1165         else
1166         {
1167            final String JavaDoc alias = aliasManager.getAlias(cntPath.getPath());
1168            StringBuffer JavaDoc keyColumn = new StringBuffer JavaDoc(20);
1169            SQLUtil.getColumnNamesClause(pkFields[0], alias, keyColumn);
1170            args = new Object JavaDoc[]{node.distinct, keyColumn.toString()};
1171         }
1172      }
1173
1174      JDBCTypeMappingMetaData.COUNT_FUNC.getFunctionSql(args, buf);
1175      return data;
1176   }
1177
1178   public Object JavaDoc visit(ASTPath node, Object JavaDoc data)
1179   {
1180      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1181      if(!node.isCMPField())
1182      {
1183         throw new IllegalStateException JavaDoc("Can only visit cmp valued path node. "
1184            + "Should have been handled at a higher level.");
1185      }
1186
1187      // make sure this is mapped to a single column
1188
switch(node.type)
1189      {
1190         case EJBQLTypes.ENTITY_TYPE:
1191         case EJBQLTypes.VALUE_CLASS_TYPE:
1192         case EJBQLTypes.UNKNOWN_TYPE:
1193            throw new IllegalStateException JavaDoc("Can not visit multi-column path " +
1194               "node. Should have been handled at a higher level.");
1195      }
1196
1197      addLeftJoinPath(node);
1198      JDBCFieldBridge cmpField = (JDBCFieldBridge) node.getCMPField();
1199      String JavaDoc alias = aliasManager.getAlias(node.getPath(node.size() - 2));
1200      SQLUtil.getColumnNamesClause(cmpField, alias, buf);
1201      return data;
1202   }
1203
1204   public Object JavaDoc visit(ASTAbstractSchema node, Object JavaDoc data)
1205   {
1206      throw new IllegalStateException JavaDoc("Can not visit abstract schema node. "
1207         + " Should have been handled at a higher level.");
1208   }
1209
1210   public Object JavaDoc visit(ASTIdentifier node, Object JavaDoc data)
1211   {
1212      throw new UnsupportedOperationException JavaDoc("Must not visit ASTIdentifier noe.");
1213   }
1214
1215   public Object JavaDoc visit(ASTParameter node, Object JavaDoc data)
1216   {
1217      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1218      Class JavaDoc type = getParameterType(node.number);
1219
1220      // make sure this is mapped to a single column
1221
int ejbqlType = EJBQLTypes.getEJBQLType(type);
1222      if(ejbqlType == EJBQLTypes.ENTITY_TYPE
1223         ||
1224         ejbqlType == EJBQLTypes.VALUE_CLASS_TYPE ||
1225         ejbqlType == EJBQLTypes.UNKNOWN_TYPE)
1226      {
1227         throw new IllegalStateException JavaDoc("Can not visit multi-column " +
1228            "parameter node. Should have been handled at a higher level.");
1229      }
1230
1231      QueryParameter param = new QueryParameter(node.number - 1, typeFactory.getJDBCType(type));
1232      inputParameters.add(param);
1233      buf.append('?');
1234
1235      return data;
1236   }
1237
1238   public Object JavaDoc visit(ASTExactNumericLiteral node, Object JavaDoc data)
1239   {
1240      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1241      buf.append(node.literal);
1242      return data;
1243   }
1244
1245   public Object JavaDoc visit(ASTApproximateNumericLiteral node, Object JavaDoc data)
1246   {
1247      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1248      buf.append(node.literal);
1249      return data;
1250   }
1251
1252   public Object JavaDoc visit(ASTStringLiteral node, Object JavaDoc data)
1253   {
1254      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1255      buf.append(node.value);
1256      return data;
1257   }
1258
1259   public Object JavaDoc visit(ASTBooleanLiteral node, Object JavaDoc data)
1260   {
1261      StringBuffer JavaDoc buf = (StringBuffer JavaDoc) data;
1262      if(node.value)
1263      {
1264         buf.append(typeMapping.getTrueMapping());
1265      }
1266      else
1267      {
1268         buf.append(typeMapping.getFalseMapping());
1269      }
1270      return data;
1271   }
1272
1273   public Object JavaDoc visit(ASTFrom from, Object JavaDoc data)
1274   {
1275      StringBuffer JavaDoc sql = (StringBuffer JavaDoc) data;
1276      from.jjtGetChild(0).jjtAccept(this, data);
1277      for(int i = 1; i < from.jjtGetNumChildren(); ++i)
1278      {
1279         from.jjtGetChild(i).jjtAccept(this, data);
1280      }
1281
1282      return data;
1283   }
1284
1285   public Object JavaDoc visit(ASTCollectionMemberDeclaration node, Object JavaDoc data)
1286   {
1287      ASTPath path = (ASTPath) node.jjtGetChild(0);
1288
1289      // assign the same alias for path and identifier
1290
ASTIdentifier id = (ASTIdentifier) node.jjtGetChild(1);
1291      String JavaDoc alias = aliasManager.getAlias(id.identifier);
1292      aliasManager.addAlias(path.getPath(), alias);
1293
1294      addInnerJoinPath(path);
1295
1296      return data;
1297   }
1298
1299   public Object JavaDoc visit(ASTRangeVariableDeclaration node, Object JavaDoc data)
1300   {
1301      ASTAbstractSchema schema = (ASTAbstractSchema) node.jjtGetChild(0);
1302      JDBCAbstractEntityBridge entity = (JDBCAbstractEntityBridge) schema.entity;
1303      ASTIdentifier id = (ASTIdentifier) node.jjtGetChild(1);
1304      declareTable(id.identifier, entity.getQualifiedTableName());
1305      return data;
1306   }
1307
1308   // Private
1309

1310   private void compareEntity(boolean not, Node fromNode, Node toNode, StringBuffer JavaDoc buf)
1311   {
1312      buf.append('(');
1313      if(not)
1314      {
1315         buf.append(SQLUtil.NOT).append('(');
1316      }
1317
1318      ASTPath fromPath = (ASTPath) fromNode;
1319      addLeftJoinPath(fromPath);
1320      String JavaDoc fromAlias = aliasManager.getAlias(fromPath.getPath());
1321      JDBCAbstractEntityBridge fromEntity = (JDBCAbstractEntityBridge) fromPath.getEntity();
1322
1323      if(toNode instanceof ASTParameter)
1324      {
1325         ASTParameter toParam = (ASTParameter) toNode;
1326
1327         // can only compare like kind entities
1328
verifyParameterEntityType(toParam.number, fromEntity);
1329
1330         inputParameters.addAll(QueryParameter.createParameters(toParam.number - 1, fromEntity));
1331
1332         SQLUtil.getWhereClause(fromEntity.getPrimaryKeyFields(), fromAlias, buf);
1333      }
1334      else
1335      {
1336         ASTPath toPath = (ASTPath) toNode;
1337         addLeftJoinPath(toPath);
1338         String JavaDoc toAlias = aliasManager.getAlias(toPath.getPath());
1339         JDBCAbstractEntityBridge toEntity = (JDBCAbstractEntityBridge) toPath.getEntity();
1340
1341         // can only compare like kind entities
1342
if(!fromEntity.equals(toEntity))
1343         {
1344            throw new IllegalStateException JavaDoc("Only like types can be "
1345               +
1346               "compared: from entity="
1347               +
1348               fromEntity.getEntityName()
1349               + " to entity=" + toEntity.getEntityName());
1350         }
1351
1352         SQLUtil.getSelfCompareWhereClause(fromEntity.getPrimaryKeyFields(), fromAlias, toAlias, buf);
1353      }
1354
1355      if(not)
1356      {
1357         buf.append(')');
1358      }
1359      buf.append(')');
1360   }
1361
1362   private void join(String JavaDoc alias, StringBuffer JavaDoc sql)
1363   {
1364      Map JavaDoc paths = (Map JavaDoc) joinPaths.get(alias);
1365      if(paths == null || paths.isEmpty())
1366      {
1367         return;
1368      }
1369
1370      for(Iterator JavaDoc iter = paths.values().iterator(); iter.hasNext();)
1371      {
1372         String JavaDoc leftAlias = alias;
1373         ASTPath path = (ASTPath) iter.next();
1374         for(int i = 1; i < path.size(); ++i)
1375         {
1376            if(path.isCMRField(i))
1377            {
1378               final String JavaDoc curPath = path.getPath(i);
1379               final String JavaDoc joinAlias = aliasManager.getAlias(curPath);
1380
1381               if(joinedAliases.add(joinAlias))
1382               {
1383                  final JDBCAbstractCMRFieldBridge cmrField = (JDBCAbstractCMRFieldBridge) path.getCMRField(i);
1384                  final JDBCAbstractEntityBridge joinEntity = (JDBCAbstractEntityBridge) cmrField.getRelatedEntity();
1385
1386                  JDBCRelationMetaData relation = cmrField.getMetaData().getRelationMetaData();
1387
1388                  String JavaDoc join = (path.innerJoin ? " INNER JOIN " : " LEFT OUTER JOIN ");
1389
1390                  if(relation.isTableMappingStyle())
1391                  {
1392                     String JavaDoc relTableAlias = aliasManager.getRelationTableAlias(curPath);
1393                     sql.append(join)
1394                        .append(cmrField.getQualifiedTableName())
1395                        .append(' ')
1396                        .append(relTableAlias)
1397                        .append(" ON ");
1398                     SQLUtil.getRelationTableJoinClause(cmrField, leftAlias, relTableAlias, sql);
1399
1400                     sql.append(join)
1401                        .append(joinEntity.getQualifiedTableName())
1402                        .append(' ')
1403                        .append(joinAlias)
1404                        .append(" ON ");
1405                     SQLUtil.getRelationTableJoinClause(cmrField.getRelatedCMRField(), joinAlias, relTableAlias, sql);
1406                  }
1407                  else
1408                  {
1409                     sql.append(join)
1410                        .append(joinEntity.getQualifiedTableName())
1411                        .append(' ')
1412                        .append(joinAlias)
1413                        .append(" ON ");
1414
1415                     SQLUtil.getJoinClause(cmrField, leftAlias, joinAlias, sql);
1416                  }
1417
1418                  join(joinAlias, sql);
1419               }
1420               leftAlias = joinAlias;
1421            }
1422         }
1423      }
1424   }
1425
1426   private void declareTable(String JavaDoc alias, String JavaDoc table)
1427   {
1428      identifierToTable.put(alias, table);
1429   }
1430
1431   private void addLeftJoinPath(ASTPath path)
1432   {
1433      if(path.size() > 1 && path.isCMRField(1))
1434      {
1435         final String JavaDoc identifier = path.getPath(0);
1436         final String JavaDoc alias = aliasManager.getAlias(identifier);
1437         Map JavaDoc paths = (Map JavaDoc) joinPaths.get(alias);
1438         if(paths == null)
1439         {
1440            paths = new HashMap JavaDoc();
1441            joinPaths.put(alias, paths);
1442         }
1443
1444         ASTPath oldPath = (ASTPath) paths.put(path, path);
1445         if(oldPath != null && oldPath.innerJoin)
1446         {
1447            path.innerJoin = true;
1448         }
1449      }
1450   }
1451
1452   private void addInnerJoinPath(ASTPath path)
1453   {
1454      if(path.size() > 1 && path.isCMRField(1))
1455      {
1456         final String JavaDoc identifier = path.getPath(0);
1457         final String JavaDoc alias = aliasManager.getAlias(identifier);
1458         Map JavaDoc paths = (Map JavaDoc) joinPaths.get(alias);
1459         if(paths == null)
1460         {
1461            paths = new HashMap JavaDoc();
1462            joinPaths.put(alias, paths);
1463         }
1464
1465         path.innerJoin = true;
1466         paths.put(path, path);
1467      }
1468   }
1469
1470   private Object JavaDoc[] childrenToStringArr(int numChildren, Node node)
1471   {
1472      Object JavaDoc[] args = new Object JavaDoc[numChildren];
1473      for(int i = 0; i < numChildren; ++i)
1474      {
1475         args[i] = node.jjtGetChild(i).jjtAccept(this, new StringBuffer JavaDoc()).toString();
1476      }
1477      return args;
1478   }
1479
1480   /**
1481    * Recursively searches for ASTPath among children.
1482    *
1483    * @param selectFunction a node implements SelectFunction
1484    * @return ASTPath child or null if there was no child of type ASTPath
1485    */

1486   private ASTPath getPathFromChildren(Node selectFunction)
1487   {
1488      for(int childInd = 0; childInd < selectFunction.jjtGetNumChildren(); ++childInd)
1489      {
1490         Node child = selectFunction.jjtGetChild(childInd);
1491         if(child instanceof ASTPath)
1492         {
1493            return (ASTPath) child;
1494         }
1495         else if(child instanceof SelectFunction)
1496         {
1497            Node path = getPathFromChildren(child);
1498            if(path != null)
1499            {
1500               return (ASTPath) path;
1501            }
1502         }
1503      }
1504      return null;
1505   }
1506
1507   private void setTypeFactory(JDBCTypeFactory typeFactory)
1508   {
1509      this.typeFactory = typeFactory;
1510      this.typeMapping = typeFactory.getTypeMapping();
1511      aliasManager = new AliasManager(typeMapping.getAliasHeaderPrefix(),
1512         typeMapping.getAliasHeaderSuffix(),
1513         typeMapping.getAliasMaxLength());
1514   }
1515
1516   private Class JavaDoc getParameterType(int index)
1517   {
1518      int zeroBasedIndex = index - 1;
1519      Class JavaDoc[] params = parameterTypes;
1520      if(zeroBasedIndex < params.length)
1521      {
1522         return params[zeroBasedIndex];
1523      }
1524      return null;
1525   }
1526
1527   // verify that parameter is the same type as the entity
1528
private void verifyParameterEntityType(int number, JDBCAbstractEntityBridge entity)
1529   {
1530      Class JavaDoc parameterType = getParameterType(number);
1531      Class JavaDoc remoteClass = entity.getRemoteInterface();
1532      Class JavaDoc localClass = entity.getLocalInterface();
1533      if((localClass == null || !localClass.isAssignableFrom(parameterType)) &&
1534         (remoteClass == null || !remoteClass.isAssignableFrom(parameterType)))
1535      {
1536         throw new IllegalStateException JavaDoc("Only like types can be compared: from entity=" +
1537            entity.getEntityName() + " to parameter type=" + parameterType);
1538      }
1539   }
1540
1541   private void reset()
1542   {
1543      returnType = null;
1544      parameterTypes = null;
1545      readAhead = null;
1546      inputParameters.clear();
1547      selectObject = null;
1548      selectManager = null;
1549      typeFactory = null;
1550      typeMapping = null;
1551      aliasManager = null;
1552      forceDistinct = false;
1553      limitParam = 0;
1554      limitValue = 0;
1555      offsetParam = 0;
1556      offsetValue = 0;
1557      leftJoinCMRList.clear();
1558      onFindCMRJoin = null;
1559      countCompositePk = false;
1560      joinPaths.clear();
1561      identifierToTable.clear();
1562      joinedAliases.clear();
1563      selectDistinct = false;
1564   }
1565}
1566
Popular Tags