Source Code Cross Referenced for SqlQueryStatement.java in  » Database-ORM » db-ojb » org » apache » ojb » broker » accesslayer » sql » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » db ojb » org.apache.ojb.broker.accesslayer.sql 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.apache.ojb.broker.accesslayer.sql;
0002:
0003:        /* Copyright 2002-2005 The Apache Software Foundation
0004:         *
0005:         * Licensed under the Apache License, Version 2.0 (the "License");
0006:         * you may not use this file except in compliance with the License.
0007:         * You may obtain a copy of the License at
0008:         *
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        import java.util.ArrayList;
0019:        import java.util.Collection;
0020:        import java.util.Enumeration;
0021:        import java.util.HashMap;
0022:        import java.util.Iterator;
0023:        import java.util.List;
0024:        import java.util.Map;
0025:
0026:        import org.apache.ojb.broker.PersistenceBrokerSQLException;
0027:        import org.apache.ojb.broker.accesslayer.JoinSyntaxTypes;
0028:        import org.apache.ojb.broker.metadata.ClassDescriptor;
0029:        import org.apache.ojb.broker.metadata.CollectionDescriptor;
0030:        import org.apache.ojb.broker.metadata.DescriptorRepository;
0031:        import org.apache.ojb.broker.metadata.FieldDescriptor;
0032:        import org.apache.ojb.broker.metadata.FieldHelper;
0033:        import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
0034:        import org.apache.ojb.broker.metadata.SuperReferenceDescriptor;
0035:        import org.apache.ojb.broker.platforms.Platform;
0036:        import org.apache.ojb.broker.query.BetweenCriteria;
0037:        import org.apache.ojb.broker.query.Criteria;
0038:        import org.apache.ojb.broker.query.ExistsCriteria;
0039:        import org.apache.ojb.broker.query.FieldCriteria;
0040:        import org.apache.ojb.broker.query.InCriteria;
0041:        import org.apache.ojb.broker.query.LikeCriteria;
0042:        import org.apache.ojb.broker.query.MtoNQuery;
0043:        import org.apache.ojb.broker.query.NullCriteria;
0044:        import org.apache.ojb.broker.query.Query;
0045:        import org.apache.ojb.broker.query.QueryByCriteria;
0046:        import org.apache.ojb.broker.query.QueryBySQL;
0047:        import org.apache.ojb.broker.query.SelectionCriteria;
0048:        import org.apache.ojb.broker.query.SqlCriteria;
0049:        import org.apache.ojb.broker.query.UserAlias;
0050:        import org.apache.ojb.broker.util.SqlHelper;
0051:        import org.apache.ojb.broker.util.SqlHelper.PathInfo;
0052:        import org.apache.ojb.broker.util.logging.Logger;
0053:        import org.apache.ojb.broker.util.logging.LoggerFactory;
0054:
0055:        /**
0056:         * Model a Statement based on Query.
0057:         *
0058:         * @author <a href="mailto:jbraeuchi@gmx.ch">Jakob Braeuchi</a>
0059:         * @version $Id: SqlQueryStatement.java,v 1.75.2.23 2005/12/22 18:25:51 brj Exp $
0060:         */
0061:        public abstract class SqlQueryStatement implements  SqlStatement,
0062:                JoinSyntaxTypes {
0063:            private static final String ALIAS_SEPARATOR = ".";
0064:            private static final String M_N_ALIAS = "M_N";
0065:            private String sql;
0066:
0067:            private SqlQueryStatement m_parentStatement;
0068:            /** the logger */
0069:            private Logger m_logger;
0070:            /** the target table of the query */
0071:            private TableAlias m_root;
0072:            /** the search table of the query */
0073:            private TableAlias m_search;
0074:            /** the query */
0075:            private QueryByCriteria m_query;
0076:            /** the mapping of paths to TableAliases. the key is built using the path and the path class hints. */
0077:            private HashMap m_pathToAlias = new HashMap();
0078:            /** the mapping of ClassDescriptor to TableAliases */
0079:            private HashMap m_cldToAlias = new HashMap();
0080:            /** maps trees of joins to criteria */
0081:            private HashMap m_joinTreeToCriteria = new HashMap();
0082:
0083:            private Platform m_platform;
0084:            private ClassDescriptor m_baseCld;
0085:            private ClassDescriptor m_searchCld;
0086:
0087:            private int m_aliasCount = 0;
0088:            protected HashMap m_attrToFld = new HashMap(); //attribute -> FieldDescriptor
0089:
0090:            /**
0091:             * Constructor for SqlCriteriaStatement.
0092:             *
0093:             * @param pf the Platform
0094:             * @param cld the ClassDescriptor
0095:             * @param query the Query
0096:             * @param logger the Logger
0097:             */
0098:            public SqlQueryStatement(Platform pf, ClassDescriptor cld,
0099:                    Query query, Logger logger) {
0100:                this (null, pf, cld, query, logger);
0101:            }
0102:
0103:            /**
0104:             * Constructor for SqlCriteriaStatement.
0105:             *
0106:             * @param parent the Parent Query
0107:             * @param pf the Platform
0108:             * @param cld the ClassDescriptor
0109:             * @param query the Query
0110:             * @param logger the Logger
0111:             */
0112:            public SqlQueryStatement(SqlQueryStatement parent, Platform pf,
0113:                    ClassDescriptor cld, Query query, Logger logger) {
0114:                m_logger = logger != null ? logger : LoggerFactory
0115:                        .getLogger(SqlQueryStatement.class);
0116:                m_parentStatement = parent;
0117:                m_query = (QueryByCriteria) query;
0118:                m_platform = pf;
0119:                m_searchCld = cld;
0120:
0121:                if ((m_query == null)
0122:                        || (m_query.getBaseClass() == m_query.getSearchClass())) {
0123:                    m_baseCld = m_searchCld;
0124:                } else {
0125:                    m_baseCld = cld.getRepository().getDescriptorFor(
0126:                            query.getBaseClass());
0127:                }
0128:
0129:                m_root = createTableAlias(m_baseCld, null, "");
0130:
0131:                // BRJ: create a special alias for the indirection table
0132:                if (m_query instanceof  MtoNQuery) {
0133:                    MtoNQuery mnQuery = (MtoNQuery) m_query;
0134:                    TableAlias mnAlias = new TableAlias(mnQuery
0135:                            .getIndirectionTable(), M_N_ALIAS);
0136:                    setTableAliasForPath(mnQuery.getIndirectionTable(), null,
0137:                            mnAlias);
0138:                }
0139:
0140:                if (m_searchCld == m_baseCld) {
0141:                    m_search = m_root;
0142:                } else {
0143:                    m_search = getTableAlias(m_query
0144:                            .getObjectProjectionAttribute(), false, null, null,
0145:                            m_query.getPathClasses());
0146:                }
0147:
0148:                // Walk the super reference-descriptor
0149:                buildSuperJoinTree(m_root, m_baseCld, "", false);
0150:
0151:                buildMultiJoinTree(m_root, m_baseCld, "", true);
0152:
0153:                // In some cases it is necessary to split the query criteria
0154:                // and then to generate UNION of several SELECTs
0155:                // We build the joinTreeToCriteria mapping,
0156:                if (query != null) {
0157:                    splitCriteria();
0158:                }
0159:            }
0160:
0161:            protected ClassDescriptor getBaseClassDescriptor() {
0162:                return m_baseCld;
0163:            }
0164:
0165:            protected ClassDescriptor getSearchClassDescriptor() {
0166:                return m_searchCld;
0167:            }
0168:
0169:            /**
0170:             * Return the TableAlias and the PathInfo for an Attribute name<br>
0171:             * field names in functions (ie: sum(name) ) are tried to resolve ie: name
0172:             * from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
0173:             * also resolve pathExpression adress.city or owner.konti.saldo
0174:             * @param attr
0175:             * @param useOuterJoins
0176:             * @param aUserAlias
0177:             * @param pathClasses
0178:             * @return ColumnInfo
0179:             */
0180:            protected AttributeInfo getAttributeInfo(String attr,
0181:                    boolean useOuterJoins, UserAlias aUserAlias, Map pathClasses) {
0182:                AttributeInfo result = new AttributeInfo();
0183:                TableAlias tableAlias;
0184:                SqlHelper.PathInfo pathInfo = SqlHelper.splitPath(attr);
0185:                String colName = pathInfo.column;
0186:                int sp;
0187:
0188:                // BRJ:
0189:                // check if we refer to an attribute in the parent query
0190:                // this prefix is temporary !
0191:                if (colName.startsWith(Criteria.PARENT_QUERY_PREFIX)
0192:                        && m_parentStatement != null) {
0193:                    String[] fieldNameRef = { colName
0194:                            .substring(Criteria.PARENT_QUERY_PREFIX.length()) };
0195:                    return m_parentStatement.getAttributeInfo(fieldNameRef[0],
0196:                            useOuterJoins, aUserAlias, pathClasses);
0197:                }
0198:
0199:                sp = colName.lastIndexOf(".");
0200:                if (sp == -1) {
0201:                    tableAlias = getRoot();
0202:                } else {
0203:                    String pathName = colName.substring(0, sp);
0204:                    String[] fieldNameRef = { colName.substring(sp + 1) };
0205:
0206:                    tableAlias = getTableAlias(pathName, useOuterJoins,
0207:                            aUserAlias, fieldNameRef, pathClasses);
0208:                    /**
0209:                     * if we have not found an alias by the pathName or
0210:                     * aliasName (if given), try again because pathName
0211:                     * may be an aliasname. it can be only and only if it is not
0212:                     * a path, which means there may be no path separators (,)
0213:                     * in the pathName.
0214:                     */
0215:                    if ((tableAlias == null)
0216:                            && (colName.lastIndexOf(".") == -1)) {
0217:                        /**
0218:                         * pathName might be an alias, so check this first
0219:                         */
0220:                        tableAlias = getTableAlias(pathName, useOuterJoins,
0221:                                new UserAlias(pathName, pathName, pathName),
0222:                                null, pathClasses);
0223:                    }
0224:
0225:                    if (tableAlias != null) {
0226:                        // correct column name to match the alias
0227:                        // productGroup.groupName -> groupName
0228:                        pathInfo.column = fieldNameRef[0];
0229:                    }
0230:                }
0231:
0232:                result.tableAlias = tableAlias;
0233:                result.pathInfo = pathInfo;
0234:                return result;
0235:            }
0236:
0237:            /**
0238:             * Answer the column name for alias and path info<br>
0239:             * if translate try to convert attribute name into column name otherwise use attribute name<br>
0240:             * if a FieldDescriptor is found for the attribute name the column name is taken from
0241:             * there prefixed with the alias (firstname -> A0.F_NAME).
0242:             */
0243:            protected String getColName(TableAlias aTableAlias,
0244:                    PathInfo aPathInfo, boolean translate) {
0245:                String result = null;
0246:
0247:                // no translation required, use attribute name
0248:                if (!translate) {
0249:                    return aPathInfo.column;
0250:                }
0251:
0252:                // BRJ: special alias for the indirection table has no ClassDescriptor 
0253:                if (aTableAlias.cld == null
0254:                        && M_N_ALIAS.equals(aTableAlias.alias)) {
0255:                    return getIndirectionTableColName(aTableAlias,
0256:                            aPathInfo.path);
0257:                }
0258:
0259:                // translate attribute name into column name
0260:                FieldDescriptor fld = getFieldDescriptor(aTableAlias, aPathInfo);
0261:
0262:                if (fld != null) {
0263:                    m_attrToFld.put(aPathInfo.path, fld);
0264:
0265:                    // added to suport the super reference descriptor
0266:                    if (!fld.getClassDescriptor().getFullTableName().equals(
0267:                            aTableAlias.table)
0268:                            && aTableAlias.hasJoins()) {
0269:                        Iterator itr = aTableAlias.joins.iterator();
0270:                        while (itr.hasNext()) {
0271:                            Join join = (Join) itr.next();
0272:                            if (join.right.table.equals(fld
0273:                                    .getClassDescriptor().getFullTableName())) {
0274:                                result = join.right.alias + "."
0275:                                        + fld.getColumnName();
0276:                                break;
0277:                            }
0278:                        }
0279:
0280:                        if (result == null) {
0281:                            result = aPathInfo.column;
0282:                        }
0283:                    } else {
0284:                        result = aTableAlias.alias + "." + fld.getColumnName();
0285:                    }
0286:                } else if ("*".equals(aPathInfo.column)) {
0287:                    result = aPathInfo.column;
0288:                } else {
0289:                    // throw new IllegalArgumentException("No Field found for : " + aPathInfo.column);
0290:                    result = aPathInfo.column;
0291:                }
0292:
0293:                return result;
0294:            }
0295:
0296:            /**
0297:             * Add the Column to the StringBuffer <br>
0298:             *
0299:             * @param aTableAlias
0300:             * @param aPathInfo
0301:             * @param translate flag to indicate translation of pathInfo
0302:             * @param buf
0303:             * @return true if appended
0304:             */
0305:            protected boolean appendColName(TableAlias aTableAlias,
0306:                    PathInfo aPathInfo, boolean translate, StringBuffer buf) {
0307:                String prefix = aPathInfo.prefix;
0308:                String suffix = aPathInfo.suffix;
0309:                String colName = getColName(aTableAlias, aPathInfo, translate);
0310:
0311:                if (prefix != null) // rebuild function contains (
0312:                {
0313:                    buf.append(prefix);
0314:                }
0315:
0316:                buf.append(colName);
0317:
0318:                if (suffix != null) // rebuild function
0319:                {
0320:                    buf.append(suffix);
0321:                }
0322:
0323:                return true;
0324:            }
0325:
0326:            /**
0327:             * Get the FieldDescriptor for the PathInfo
0328:             *
0329:             * @param aTableAlias
0330:             * @param aPathInfo
0331:             * @return FieldDescriptor
0332:             */
0333:            protected FieldDescriptor getFieldDescriptor(
0334:                    TableAlias aTableAlias, PathInfo aPathInfo) {
0335:                FieldDescriptor fld = null;
0336:                String colName = aPathInfo.column;
0337:
0338:                if (aTableAlias != null) {
0339:                    fld = aTableAlias.cld.getFieldDescriptorByName(colName);
0340:                    if (fld == null) {
0341:                        ObjectReferenceDescriptor ord = aTableAlias.cld
0342:                                .getObjectReferenceDescriptorByName(colName);
0343:                        if (ord != null) {
0344:                            fld = getFldFromReference(aTableAlias, ord);
0345:                        } else {
0346:                            fld = getFldFromJoin(aTableAlias, colName);
0347:                        }
0348:                    }
0349:                }
0350:
0351:                return fld;
0352:            }
0353:
0354:            /**
0355:             * Get FieldDescriptor from joined superclass.
0356:             */
0357:            private FieldDescriptor getFldFromJoin(TableAlias aTableAlias,
0358:                    String aColName) {
0359:                FieldDescriptor fld = null;
0360:
0361:                // Search Join Structure for attribute
0362:                if (aTableAlias.joins != null) {
0363:                    Iterator itr = aTableAlias.joins.iterator();
0364:                    while (itr.hasNext()) {
0365:                        Join join = (Join) itr.next();
0366:                        ClassDescriptor cld = join.right.cld;
0367:
0368:                        if (cld != null) {
0369:                            fld = cld.getFieldDescriptorByName(aColName);
0370:                            if (fld != null) {
0371:                                break;
0372:                            }
0373:
0374:                        }
0375:                    }
0376:                }
0377:                return fld;
0378:            }
0379:
0380:            /**
0381:             * Get FieldDescriptor from Reference
0382:             */
0383:            private FieldDescriptor getFldFromReference(TableAlias aTableAlias,
0384:                    ObjectReferenceDescriptor anOrd) {
0385:                FieldDescriptor fld = null;
0386:
0387:                if (aTableAlias == getRoot()) {
0388:                    // no path expression
0389:                    FieldDescriptor[] fk = anOrd
0390:                            .getForeignKeyFieldDescriptors(aTableAlias.cld);
0391:                    if (fk.length > 0) {
0392:                        fld = fk[0];
0393:                    }
0394:                } else {
0395:                    // attribute with path expression
0396:                    /**
0397:                     * MBAIRD
0398:                     * potentially people are referring to objects, not to the object's primary key, 
0399:                     * and then we need to take the primary key attribute of the referenced object 
0400:                     * to help them out.
0401:                     */
0402:                    ClassDescriptor cld = aTableAlias.cld.getRepository()
0403:                            .getDescriptorFor(anOrd.getItemClass());
0404:                    if (cld != null) {
0405:                        fld = aTableAlias.cld.getFieldDescriptorByName(cld
0406:                                .getPkFields()[0].getPersistentField()
0407:                                .getName());
0408:                    }
0409:                }
0410:
0411:                return fld;
0412:            }
0413:
0414:            /**
0415:             * Append the appropriate ColumnName to the buffer<br>
0416:             * if a FIELDDESCRIPTOR is found for the Criteria the colName is taken from
0417:             * there otherwise its taken from Criteria. <br>
0418:             * field names in functions (ie: sum(name) ) are tried to resolve
0419:             * ie: name from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
0420:             * also resolve pathExpression adress.city or owner.konti.saldo
0421:             */
0422:            protected boolean appendColName(String attr, boolean useOuterJoins,
0423:                    UserAlias aUserAlias, StringBuffer buf) {
0424:                AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins,
0425:                        aUserAlias, getQuery().getPathClasses());
0426:                TableAlias tableAlias = attrInfo.tableAlias;
0427:
0428:                return appendColName(tableAlias, attrInfo.pathInfo,
0429:                        (tableAlias != null), buf);
0430:            }
0431:
0432:            /**
0433:             * Append the appropriate ColumnName to the buffer<br>
0434:             * if a FIELDDESCRIPTOR is found for the Criteria the colName is taken from
0435:             * there otherwise its taken from Criteria. <br>
0436:             * field names in functions (ie: sum(name) ) are tried to resolve
0437:             * ie: name from FIELDDESCRIPTOR , UPPER(name_test) from Criteria<br>
0438:             * also resolve pathExpression adress.city or owner.konti.saldo
0439:             */
0440:            protected boolean appendColName(String attr, String attrAlias,
0441:                    boolean useOuterJoins, UserAlias aUserAlias,
0442:                    StringBuffer buf) {
0443:                AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins,
0444:                        aUserAlias, getQuery().getPathClasses());
0445:                TableAlias tableAlias = attrInfo.tableAlias;
0446:                PathInfo pi = attrInfo.pathInfo;
0447:
0448:                if (pi.suffix != null) {
0449:                    pi.suffix = pi.suffix + " as " + attrAlias;
0450:                } else {
0451:                    pi.suffix = " as " + attrAlias;
0452:                }
0453:
0454:                return appendColName(tableAlias, pi, true, buf);
0455:            }
0456:
0457:            /**
0458:             * Builds the Join for columns if they are not found among the existingColumns.
0459:             * @param columns the list of columns represented by Criteria.Field to ensure
0460:             * @param existingColumns the list of column names (String) that are already appended
0461:             */
0462:            protected void ensureColumns(List columns, List existingColumns) {
0463:                if (columns == null || columns.isEmpty()) {
0464:                    return;
0465:                }
0466:
0467:                Iterator iter = columns.iterator();
0468:
0469:                while (iter.hasNext()) {
0470:                    FieldHelper cf = (FieldHelper) iter.next();
0471:                    if (!existingColumns.contains(cf.name)) {
0472:                        getAttributeInfo(cf.name, false, null, getQuery()
0473:                                .getPathClasses());
0474:                    }
0475:                }
0476:            }
0477:
0478:            /**
0479:             * Builds the Join for columns if they are not found among the existingColumns.
0480:             * These <b>columns are added to the statement</b> using a column-alias "ojb_col_x", 
0481:             * x being the number of existing columns
0482:             * @param columns the list of columns represented by Criteria.Field to ensure
0483:             * @param existingColumns the list of column names (String) that are already appended
0484:             * @param buf the statement
0485:             * @return List of existingColumns including ojb_col_x
0486:             */
0487:            protected List ensureColumns(List columns, List existingColumns,
0488:                    StringBuffer buf) {
0489:                if (columns == null || columns.isEmpty()) {
0490:                    return existingColumns;
0491:                }
0492:
0493:                Iterator iter = columns.iterator();
0494:                int ojb_col = existingColumns.size() + 1;
0495:
0496:                while (iter.hasNext()) {
0497:                    FieldHelper cf = (FieldHelper) iter.next();
0498:                    if (!existingColumns.contains(cf.name)) {
0499:                        existingColumns.add(cf.name);
0500:
0501:                        buf.append(",");
0502:                        appendColName(cf.name, "ojb_col_" + ojb_col, false,
0503:                                null, buf);
0504:                        ojb_col++;
0505:                    }
0506:                }
0507:
0508:                return existingColumns;
0509:            }
0510:
0511:            /**
0512:             * appends a WHERE-clause to the Statement
0513:             * @param where
0514:             * @param crit
0515:             * @param stmt
0516:             */
0517:            protected void appendWhereClause(StringBuffer where, Criteria crit,
0518:                    StringBuffer stmt) {
0519:                if (where.length() == 0) {
0520:                    where = null;
0521:                }
0522:
0523:                if (where != null || (crit != null && !crit.isEmpty())) {
0524:                    stmt.append(" WHERE ");
0525:                    appendClause(where, crit, stmt);
0526:                }
0527:            }
0528:
0529:            /**
0530:             * appends a HAVING-clause to the Statement
0531:             * @param having
0532:             * @param crit
0533:             * @param stmt
0534:             */
0535:            protected void appendHavingClause(StringBuffer having,
0536:                    Criteria crit, StringBuffer stmt) {
0537:                if (having.length() == 0) {
0538:                    having = null;
0539:                }
0540:
0541:                if (having != null || crit != null) {
0542:                    stmt.append(" HAVING ");
0543:                    appendClause(having, crit, stmt);
0544:                }
0545:            }
0546:
0547:            /**
0548:             * appends a WHERE/HAVING-clause to the Statement
0549:             * @param clause
0550:             * @param crit
0551:             * @param stmt
0552:             */
0553:            protected void appendClause(StringBuffer clause, Criteria crit,
0554:                    StringBuffer stmt) {
0555:                /**
0556:                 * MBAIRD
0557:                 * when generating the "WHERE/HAVING" clause we need to append the criteria for multi-mapped
0558:                 * tables. We only need to do this for the root classdescriptor and not for joined tables
0559:                 * because we assume you cannot make a relation of the wrong type upon insertion. Of course,
0560:                 * you COULD mess the data up manually and this would cause a problem.
0561:                 */
0562:
0563:                if (clause != null) {
0564:                    stmt.append(clause.toString());
0565:                }
0566:                if (crit != null) {
0567:                    if (clause == null) {
0568:                        stmt.append(asSQLStatement(crit));
0569:                    } else {
0570:                        stmt.append(" AND (");
0571:                        stmt.append(asSQLStatement(crit));
0572:                        stmt.append(")");
0573:                    }
0574:
0575:                }
0576:            }
0577:
0578:            /**
0579:             * Create SQL-String based on Criteria
0580:             */
0581:            private String asSQLStatement(Criteria crit) {
0582:                Enumeration e = crit.getElements();
0583:                StringBuffer statement = new StringBuffer();
0584:
0585:                while (e.hasMoreElements()) {
0586:                    Object o = e.nextElement();
0587:                    if (o instanceof  Criteria) {
0588:                        Criteria pc = (Criteria) o;
0589:
0590:                        if (pc.isEmpty()) {
0591:                            continue; //skip empty criteria
0592:                        }
0593:
0594:                        String addAtStart = "";
0595:                        String addAtEnd = "";
0596:
0597:                        // need to add parenthesises?
0598:                        if (pc.isEmbraced()) {
0599:                            addAtStart = " (";
0600:                            addAtEnd = ")";
0601:                        }
0602:
0603:                        switch (pc.getType()) {
0604:                        case (Criteria.OR): {
0605:                            if (statement.length() > 0) {
0606:                                statement.append(" OR ");
0607:                            }
0608:                            statement.append(addAtStart);
0609:                            statement.append(asSQLStatement(pc));
0610:                            statement.append(addAtEnd);
0611:                            break;
0612:                        }
0613:                        case (Criteria.AND): {
0614:                            if (statement.length() > 0) {
0615:                                statement.insert(0, "( ");
0616:                                statement.append(") AND ");
0617:                            }
0618:                            statement.append(addAtStart);
0619:                            statement.append(asSQLStatement(pc));
0620:                            statement.append(addAtEnd);
0621:                            break;
0622:                        }
0623:                        }
0624:                    } else {
0625:                        SelectionCriteria c = (SelectionCriteria) o;
0626:                        if (statement.length() > 0) {
0627:                            statement.insert(0, "(");
0628:                            statement.append(") AND ");
0629:                        }
0630:                        appendSQLClause(c, statement);
0631:                    }
0632:                } // while
0633:
0634:                // BRJ : negative Criteria surrounded by NOT (...)
0635:                if (crit.isNegative()) {
0636:                    statement.insert(0, " NOT (");
0637:                    statement.append(")");
0638:                }
0639:
0640:                return (statement.length() == 0 ? null : statement.toString());
0641:            }
0642:
0643:            /**
0644:             * Answer the SQL-Clause for a BetweenCriteria
0645:             *
0646:             * @param alias
0647:             * @param pathInfo
0648:             * @param c BetweenCriteria
0649:             * @param buf
0650:             */
0651:            private void appendBetweenCriteria(TableAlias alias,
0652:                    PathInfo pathInfo, BetweenCriteria c, StringBuffer buf) {
0653:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0654:                buf.append(c.getClause());
0655:                appendParameter(c.getValue(), buf);
0656:                buf.append(" AND ");
0657:                appendParameter(c.getValue2(), buf);
0658:            }
0659:
0660:            /**
0661:             * Answer the SQL-Clause for an ExistsCriteria
0662:             * @param c ExistsCriteria
0663:             */
0664:            private void appendExistsCriteria(ExistsCriteria c, StringBuffer buf) {
0665:                Query subQuery = (Query) c.getValue();
0666:
0667:                buf.append(c.getClause());
0668:                appendSubQuery(subQuery, buf);
0669:            }
0670:
0671:            /**
0672:             * Answer the SQL-Clause for a FieldCriteria<br>
0673:             * The value of the FieldCriteria will be translated
0674:             *
0675:             * @param alias
0676:             * @param pathInfo
0677:             * @param c ColumnCriteria
0678:             * @param buf
0679:             */
0680:            private void appendFieldCriteria(TableAlias alias,
0681:                    PathInfo pathInfo, FieldCriteria c, StringBuffer buf) {
0682:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0683:                buf.append(c.getClause());
0684:
0685:                if (c.isTranslateField()) {
0686:                    appendColName((String) c.getValue(), false, c
0687:                            .getUserAlias(), buf);
0688:                } else {
0689:                    buf.append(c.getValue());
0690:                }
0691:            }
0692:
0693:            /**
0694:             * Get the column name from the indirection table.
0695:             * @param mnAlias 
0696:             * @param path
0697:             */
0698:            private String getIndirectionTableColName(TableAlias mnAlias,
0699:                    String path) {
0700:                int dotIdx = path.lastIndexOf(".");
0701:                String column = path.substring(dotIdx);
0702:                return mnAlias.alias + column;
0703:            }
0704:
0705:            /**
0706:             * Answer the SQL-Clause for an InCriteria
0707:             *
0708:             * @param alias
0709:             * @param pathInfo
0710:             * @param c InCriteria
0711:             * @param buf
0712:             */
0713:            private void appendInCriteria(TableAlias alias, PathInfo pathInfo,
0714:                    InCriteria c, StringBuffer buf) {
0715:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0716:                buf.append(c.getClause());
0717:
0718:                if (c.getValue() instanceof  Collection) {
0719:                    Object[] values = ((Collection) c.getValue()).toArray();
0720:                    int size = ((Collection) c.getValue()).size();
0721:
0722:                    buf.append("(");
0723:                    if (size > 0) {
0724:                        for (int i = 0; i < size - 1; i++) {
0725:                            appendParameter(values[i], buf);
0726:                            buf.append(",");
0727:                        }
0728:                        appendParameter(values[size - 1], buf);
0729:                    }
0730:                    buf.append(")");
0731:                } else {
0732:                    appendParameter(c.getValue(), buf);
0733:                }
0734:            }
0735:
0736:            /**
0737:             * Answer the SQL-Clause for a NullCriteria
0738:             *
0739:             * @param alias
0740:             * @param pathInfo
0741:             * @param c NullCriteria
0742:             * @param buf
0743:             */
0744:            private void appendNullCriteria(TableAlias alias,
0745:                    PathInfo pathInfo, NullCriteria c, StringBuffer buf) {
0746:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0747:                buf.append(c.getClause());
0748:            }
0749:
0750:            /**
0751:             * Answer the SQL-Clause for a SqlCriteria
0752:             *
0753:             */
0754:            private void appendSQLCriteria(SqlCriteria c, StringBuffer buf) {
0755:                buf.append(c.getClause());
0756:            }
0757:
0758:            /**
0759:             * Answer the SQL-Clause for a SelectionCriteria
0760:             *
0761:             * @param c
0762:             * @param buf
0763:             */
0764:            private void appendSelectionCriteria(TableAlias alias,
0765:                    PathInfo pathInfo, SelectionCriteria c, StringBuffer buf) {
0766:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0767:                buf.append(c.getClause());
0768:                appendParameter(c.getValue(), buf);
0769:            }
0770:
0771:            /**
0772:             * Answer the SQL-Clause for a LikeCriteria
0773:             *
0774:             * @param c
0775:             * @param buf
0776:             */
0777:            private void appendLikeCriteria(TableAlias alias,
0778:                    PathInfo pathInfo, LikeCriteria c, StringBuffer buf) {
0779:                appendColName(alias, pathInfo, c.isTranslateAttribute(), buf);
0780:                buf.append(c.getClause());
0781:                appendParameter(c.getValue(), buf);
0782:
0783:                buf.append(m_platform.getEscapeClause(c));
0784:            }
0785:
0786:            /**
0787:             * Answer the SQL-Clause for a SelectionCriteria
0788:             *
0789:             * @param alias
0790:             * @param pathInfo
0791:             * @param c SelectionCriteria
0792:             * @param buf
0793:             */
0794:            protected void appendCriteria(TableAlias alias, PathInfo pathInfo,
0795:                    SelectionCriteria c, StringBuffer buf) {
0796:                if (c instanceof  FieldCriteria) {
0797:                    appendFieldCriteria(alias, pathInfo, (FieldCriteria) c, buf);
0798:                } else if (c instanceof  NullCriteria) {
0799:                    appendNullCriteria(alias, pathInfo, (NullCriteria) c, buf);
0800:                } else if (c instanceof  BetweenCriteria) {
0801:                    appendBetweenCriteria(alias, pathInfo, (BetweenCriteria) c,
0802:                            buf);
0803:                } else if (c instanceof  InCriteria) {
0804:                    appendInCriteria(alias, pathInfo, (InCriteria) c, buf);
0805:                } else if (c instanceof  SqlCriteria) {
0806:                    appendSQLCriteria((SqlCriteria) c, buf);
0807:                } else if (c instanceof  ExistsCriteria) {
0808:                    appendExistsCriteria((ExistsCriteria) c, buf);
0809:                } else if (c instanceof  LikeCriteria) {
0810:                    appendLikeCriteria(alias, pathInfo, (LikeCriteria) c, buf);
0811:                } else {
0812:                    appendSelectionCriteria(alias, pathInfo, c, buf);
0813:                }
0814:            }
0815:
0816:            /**
0817:             * Answer the SQL-Clause for a SelectionCriteria
0818:             * If the Criteria references a class with extents an OR-Clause is
0819:             * added for each extent
0820:             * @param c SelectionCriteria
0821:             */
0822:            protected void appendSQLClause(SelectionCriteria c, StringBuffer buf) {
0823:                // BRJ : handle SqlCriteria
0824:                if (c instanceof  SqlCriteria) {
0825:                    buf.append(c.getAttribute());
0826:                    return;
0827:                }
0828:
0829:                // BRJ : criteria attribute is a query
0830:                if (c.getAttribute() instanceof  Query) {
0831:                    Query q = (Query) c.getAttribute();
0832:                    buf.append("(");
0833:                    buf.append(getSubQuerySQL(q));
0834:                    buf.append(")");
0835:                    buf.append(c.getClause());
0836:                    appendParameter(c.getValue(), buf);
0837:                    return;
0838:                }
0839:
0840:                AttributeInfo attrInfo = getAttributeInfo((String) c
0841:                        .getAttribute(), false, c.getUserAlias(), c
0842:                        .getPathClasses());
0843:                TableAlias alias = attrInfo.tableAlias;
0844:
0845:                if (alias != null) {
0846:                    boolean hasExtents = alias.hasExtents();
0847:
0848:                    if (hasExtents) {
0849:                        // BRJ : surround with braces if alias has extents
0850:                        buf.append("(");
0851:                        appendCriteria(alias, attrInfo.pathInfo, c, buf);
0852:
0853:                        c.setNumberOfExtentsToBind(alias.extents.size());
0854:                        Iterator iter = alias.iterateExtents();
0855:                        while (iter.hasNext()) {
0856:                            TableAlias tableAlias = (TableAlias) iter.next();
0857:                            buf.append(" OR ");
0858:                            appendCriteria(tableAlias, attrInfo.pathInfo, c,
0859:                                    buf);
0860:                        }
0861:                        buf.append(")");
0862:                    } else {
0863:                        // no extents
0864:                        appendCriteria(alias, attrInfo.pathInfo, c, buf);
0865:                    }
0866:                } else {
0867:                    // alias null
0868:                    appendCriteria(alias, attrInfo.pathInfo, c, buf);
0869:                }
0870:
0871:            }
0872:
0873:            /**
0874:             * Append the Parameter
0875:             * Add the place holder ? or the SubQuery
0876:             * @param value the value of the criteria
0877:             */
0878:            private void appendParameter(Object value, StringBuffer buf) {
0879:                if (value instanceof  Query) {
0880:                    appendSubQuery((Query) value, buf);
0881:                } else {
0882:                    buf.append("?");
0883:                }
0884:            }
0885:
0886:            /**
0887:             * Append a SubQuery the SQL-Clause
0888:             * @param subQuery the subQuery value of SelectionCriteria
0889:             */
0890:            private void appendSubQuery(Query subQuery, StringBuffer buf) {
0891:                buf.append(" (");
0892:                buf.append(getSubQuerySQL(subQuery));
0893:                buf.append(") ");
0894:            }
0895:
0896:            /**
0897:             * Convert subQuery to SQL
0898:             * @param subQuery the subQuery value of SelectionCriteria
0899:             */
0900:            private String getSubQuerySQL(Query subQuery) {
0901:                ClassDescriptor cld = getRoot().cld.getRepository()
0902:                        .getDescriptorFor(subQuery.getSearchClass());
0903:                String sql;
0904:
0905:                if (subQuery instanceof  QueryBySQL) {
0906:                    sql = ((QueryBySQL) subQuery).getSql();
0907:                } else {
0908:                    sql = new SqlSelectStatement(this , m_platform, cld,
0909:                            subQuery, m_logger).getStatement();
0910:                }
0911:
0912:                return sql;
0913:            }
0914:
0915:            /**
0916:             * Get TableAlias by the path from the target table of the query.
0917:             * @param aPath the path from the target table of the query to this TableAlias.
0918:             * @param useOuterJoins use outer join to join this table with the previous
0919:             * table in the path.
0920:             * @param aUserAlias if specified, overrides alias in crit
0921:             * @param fieldRef String[1] contains the field name.
0922:             * In the case of related table's primary key the "related.pk" attribute
0923:             * must not add new join, but use the value of foreign key
0924:             * @param pathClasses the hints 
0925:             */
0926:            private TableAlias getTableAlias(String aPath,
0927:                    boolean useOuterJoins, UserAlias aUserAlias,
0928:                    String[] fieldRef, Map pathClasses) {
0929:                TableAlias curr, prev, indirect;
0930:                String attr, attrPath = null;
0931:                ObjectReferenceDescriptor ord;
0932:                CollectionDescriptor cod;
0933:                ClassDescriptor cld;
0934:                Object[] prevKeys;
0935:                Object[] keys;
0936:                ArrayList descriptors;
0937:                boolean outer = useOuterJoins;
0938:                int pathLength;
0939:                List hintClasses = null;
0940:                String pathAlias = aUserAlias == null ? null : aUserAlias
0941:                        .getAlias(aPath);
0942:
0943:                if (pathClasses != null) {
0944:                    hintClasses = (List) pathClasses.get(aPath);
0945:                }
0946:
0947:                curr = getTableAliasForPath(aPath, pathAlias, hintClasses);
0948:                if (curr != null) {
0949:                    return curr;
0950:                }
0951:
0952:                descriptors = getRoot().cld.getAttributeDescriptorsForPath(
0953:                        aPath, pathClasses);
0954:                prev = getRoot();
0955:
0956:                if (descriptors == null || descriptors.size() == 0) {
0957:                    if (prev.hasJoins()) {
0958:                        for (Iterator itr = prev.iterateJoins(); itr.hasNext();) {
0959:                            prev = ((Join) itr.next()).left;
0960:                            descriptors = prev.cld
0961:                                    .getAttributeDescriptorsForPath(aPath,
0962:                                            pathClasses);
0963:                            if (descriptors.size() > 0) {
0964:                                break;
0965:                            }
0966:                        }
0967:                    }
0968:                }
0969:
0970:                pathLength = descriptors.size();
0971:                for (int i = 0; i < pathLength; i++) {
0972:                    if (!(descriptors.get(i) instanceof  ObjectReferenceDescriptor)) {
0973:                        // only use Collection- and ObjectReferenceDescriptor
0974:                        continue;
0975:                    }
0976:
0977:                    ord = (ObjectReferenceDescriptor) descriptors.get(i);
0978:                    attr = ord.getAttributeName();
0979:                    if (attrPath == null) {
0980:                        attrPath = attr;
0981:                    } else {
0982:                        attrPath = attrPath + "." + attr;
0983:                    }
0984:
0985:                    // use clas hints for path
0986:                    if (pathClasses != null) {
0987:                        hintClasses = (List) pathClasses.get(attrPath);
0988:                    }
0989:
0990:                    // look for outer join hint
0991:                    outer = outer || getQuery().isPathOuterJoin(attrPath);
0992:
0993:                    // look for 1:n or m:n
0994:                    if (ord instanceof  CollectionDescriptor) {
0995:                        cod = (CollectionDescriptor) ord;
0996:                        cld = getItemClassDescriptor(cod, hintClasses);
0997:
0998:                        if (!cod.isMtoNRelation()) {
0999:                            prevKeys = prev.cld.getPkFields();
1000:                            keys = cod.getForeignKeyFieldDescriptors(cld);
1001:                        } else {
1002:                            String mnAttrPath = attrPath + "*";
1003:                            String mnUserAlias = (aUserAlias == null ? null
1004:                                    : aUserAlias + "*");
1005:                            indirect = getTableAliasForPath(mnAttrPath,
1006:                                    mnUserAlias, null);
1007:                            if (indirect == null) {
1008:                                indirect = createTableAlias(cod
1009:                                        .getIndirectionTable(), mnAttrPath,
1010:                                        mnUserAlias);
1011:
1012:                                // we need two Joins for m:n
1013:                                // 1.) prev class to indirectionTable
1014:                                prevKeys = prev.cld.getPkFields();
1015:                                keys = cod.getFksToThisClass();
1016:                                addJoin(prev, prevKeys, indirect, keys, outer,
1017:                                        attr + "*");
1018:                            }
1019:                            // 2.) indirectionTable to the current Class
1020:                            prev = indirect;
1021:                            prevKeys = cod.getFksToItemClass();
1022:                            keys = cld.getPkFields();
1023:                        }
1024:                    } else {
1025:                        // must be n:1 or 1:1
1026:                        cld = getItemClassDescriptor(ord, hintClasses);
1027:
1028:                        // BRJ : if ord is taken from 'super' we have to change prev accordingly
1029:                        if (!prev.cld.equals(ord.getClassDescriptor())) {
1030:                            TableAlias ordAlias = getTableAliasForClassDescriptor(ord
1031:                                    .getClassDescriptor());
1032:                            Join join = prev.getJoin(ordAlias);
1033:                            if (join != null) {
1034:                                join.isOuter = join.isOuter || outer;
1035:                            }
1036:                            prev = ordAlias;
1037:                        }
1038:
1039:                        prevKeys = ord.getForeignKeyFieldDescriptors(prev.cld);
1040:                        keys = cld.getPkFields();
1041:
1042:                        // [olegnitz]
1043:                        // a special case: the last element of the path is
1044:                        // reference and the field is one of PK fields =>
1045:                        // use the correspondent foreign key field, don't add the join
1046:                        if ((fieldRef != null) && (i == (pathLength - 1))) {
1047:                            FieldDescriptor[] pk = cld.getPkFields();
1048:
1049:                            for (int j = 0; j < pk.length; j++) {
1050:                                if (pk[j].getAttributeName()
1051:                                        .equals(fieldRef[0])) {
1052:                                    fieldRef[0] = ((FieldDescriptor) prevKeys[j])
1053:                                            .getAttributeName();
1054:                                    return prev;
1055:                                }
1056:                            }
1057:                        }
1058:                    }
1059:
1060:                    pathAlias = aUserAlias == null ? null : aUserAlias
1061:                            .getAlias(attrPath);
1062:                    curr = getTableAliasForPath(attrPath, pathAlias,
1063:                            hintClasses);
1064:
1065:                    if (curr == null) {
1066:                        curr = createTableAlias(cld, attrPath, pathAlias,
1067:                                hintClasses);
1068:
1069:                        outer = outer || (curr.cld == prev.cld)
1070:                                || curr.hasExtents() || useOuterJoins;
1071:                        addJoin(prev, prevKeys, curr, keys, outer, attr);
1072:
1073:                        buildSuperJoinTree(curr, cld, aPath, outer);
1074:                    }
1075:
1076:                    prev = curr;
1077:                }
1078:
1079:                m_logger.debug("Result of getTableAlias(): " + curr);
1080:                return curr;
1081:            }
1082:
1083:            /**
1084:             * add a join between two aliases
1085:             * 
1086:             * TODO BRJ : This needs refactoring, it looks kind of weird
1087:             *
1088:             * no extents
1089:             * A1   -> A2
1090:             *
1091:             * extents on the right
1092:             * A1   -> A2
1093:             * A1   -> A2E0
1094:             *
1095:             * extents on the left : copy alias on right, extents point to copies
1096:             * A1   -> A2
1097:             * A1E0 -> A2C0
1098:             *
1099:             * extents on the left and right
1100:             * A1   -> A2
1101:             * A1   -> A2E0
1102:             * A1E0 -> A2C0
1103:             * A1E0 -> A2E0C0
1104:             *
1105:             * @param left
1106:             * @param leftKeys
1107:             * @param right
1108:             * @param rightKeys
1109:             * @param outer
1110:             * @param name
1111:             */
1112:            private void addJoin(TableAlias left, Object[] leftKeys,
1113:                    TableAlias right, Object[] rightKeys, boolean outer,
1114:                    String name) {
1115:                TableAlias extAlias, rightCopy;
1116:
1117:                left.addJoin(new Join(left, leftKeys, right, rightKeys, outer,
1118:                        name));
1119:
1120:                // build join between left and extents of right
1121:                if (right.hasExtents()) {
1122:                    for (int i = 0; i < right.extents.size(); i++) {
1123:                        extAlias = (TableAlias) right.extents.get(i);
1124:                        FieldDescriptor[] extKeys = getExtentFieldDescriptors(
1125:                                extAlias, (FieldDescriptor[]) rightKeys);
1126:
1127:                        left.addJoin(new Join(left, leftKeys, extAlias,
1128:                                extKeys, true, name));
1129:                    }
1130:                }
1131:
1132:                // we need to copy the alias on the right for each extent on the left
1133:                if (left.hasExtents()) {
1134:                    for (int i = 0; i < left.extents.size(); i++) {
1135:                        extAlias = (TableAlias) left.extents.get(i);
1136:                        FieldDescriptor[] extKeys = getExtentFieldDescriptors(
1137:                                extAlias, (FieldDescriptor[]) leftKeys);
1138:                        rightCopy = right.copy("C" + i);
1139:
1140:                        // copies are treated like normal extents
1141:                        right.extents.add(rightCopy);
1142:                        right.extents.addAll(rightCopy.extents);
1143:
1144:                        addJoin(extAlias, extKeys, rightCopy, rightKeys, true,
1145:                                name);
1146:                    }
1147:                }
1148:            }
1149:
1150:            /**
1151:             * Get the FieldDescriptors of the extent based on the FieldDescriptors of the parent.
1152:             */
1153:            private FieldDescriptor[] getExtentFieldDescriptors(
1154:                    TableAlias extAlias, FieldDescriptor[] fds) {
1155:                FieldDescriptor[] result = new FieldDescriptor[fds.length];
1156:
1157:                for (int i = 0; i < fds.length; i++) {
1158:                    result[i] = extAlias.cld.getFieldDescriptorByName(fds[i]
1159:                            .getAttributeName());
1160:                }
1161:
1162:                return result;
1163:            }
1164:
1165:            private char getAliasChar() {
1166:                char result = 'A';
1167:
1168:                if (m_parentStatement != null) {
1169:                    result = (char) (m_parentStatement.getAliasChar() + 1);
1170:                }
1171:
1172:                return result;
1173:            }
1174:
1175:            /**
1176:             * Create a TableAlias for path or userAlias
1177:             * @param aCld
1178:             * @param aPath
1179:             * @param aUserAlias
1180:             * @param hints a List os Class objects to be used as hints for path expressions
1181:             * @return TableAlias
1182:             *
1183:             */
1184:            private TableAlias createTableAlias(ClassDescriptor aCld,
1185:                    String aPath, String aUserAlias, List hints) {
1186:                if (aUserAlias == null) {
1187:                    return createTableAlias(aCld, hints, aPath);
1188:                } else {
1189:                    return createTableAlias(aCld, hints, aUserAlias
1190:                            + ALIAS_SEPARATOR + aPath);
1191:                }
1192:            }
1193:
1194:            /**
1195:             * Create new TableAlias for path
1196:             * @param cld the class descriptor for the TableAlias
1197:             * @param path the path from the target table of the query to this TableAlias.
1198:             * @param hints a List of Class objects to be used on path expressions
1199:             */
1200:            private TableAlias createTableAlias(ClassDescriptor cld,
1201:                    List hints, String path) {
1202:                TableAlias alias;
1203:                boolean lookForExtents = false;
1204:
1205:                if (!cld.getExtentClasses().isEmpty() && path.length() > 0) {
1206:                    lookForExtents = true;
1207:                }
1208:
1209:                String aliasName = String.valueOf(getAliasChar())
1210:                        + m_aliasCount++; // m_pathToAlias.size();
1211:                alias = new TableAlias(cld, aliasName, lookForExtents, hints);
1212:
1213:                setTableAliasForPath(path, hints, alias);
1214:                return alias;
1215:            }
1216:
1217:            /**
1218:             * Create a TableAlias for path or userAlias
1219:             * @param aTable
1220:             * @param aPath
1221:             * @param aUserAlias
1222:             * @return TableAlias
1223:             */
1224:            private TableAlias createTableAlias(String aTable, String aPath,
1225:                    String aUserAlias) {
1226:                if (aUserAlias == null) {
1227:                    return createTableAlias(aTable, aPath);
1228:                } else {
1229:                    return createTableAlias(aTable, aUserAlias
1230:                            + ALIAS_SEPARATOR + aPath);
1231:                }
1232:            }
1233:
1234:            /**
1235:             * Create new TableAlias for path
1236:             * @param table the table name
1237:             * @param path the path from the target table of the query to this TableAlias.
1238:             */
1239:            private TableAlias createTableAlias(String table, String path) {
1240:                TableAlias alias;
1241:
1242:                if (table == null) {
1243:                    getLogger().warn(
1244:                            "Creating TableAlias without table for path: "
1245:                                    + path);
1246:                }
1247:
1248:                String aliasName = String.valueOf(getAliasChar())
1249:                        + m_aliasCount++; // + m_pathToAlias.size();
1250:                alias = new TableAlias(table, aliasName);
1251:                setTableAliasForPath(path, null, alias);
1252:                m_logger.debug("createTableAlias2: path: " + path
1253:                        + " tableAlias: " + alias);
1254:
1255:                return alias;
1256:            }
1257:
1258:            /**
1259:             * Answer the TableAlias for aPath
1260:             * @param aPath
1261:             * @param hintClasses 
1262:             * @return TableAlias, null if none
1263:             */
1264:            private TableAlias getTableAliasForPath(String aPath,
1265:                    List hintClasses) {
1266:                return (TableAlias) m_pathToAlias.get(buildAliasKey(aPath,
1267:                        hintClasses));
1268:            }
1269:
1270:            /**
1271:             * Set the TableAlias for aPath
1272:             * @param aPath
1273:             * @param hintClasses 
1274:             * @param TableAlias
1275:             */
1276:            private void setTableAliasForPath(String aPath, List hintClasses,
1277:                    TableAlias anAlias) {
1278:                m_pathToAlias.put(buildAliasKey(aPath, hintClasses), anAlias);
1279:            }
1280:
1281:            /**
1282:             * Build the key for the TableAlias based on the path and the hints
1283:             * @param aPath
1284:             * @param hintClasses
1285:             * @return the key for the TableAlias
1286:             */
1287:            private String buildAliasKey(String aPath, List hintClasses) {
1288:                if (hintClasses == null || hintClasses.isEmpty()) {
1289:                    return aPath;
1290:                }
1291:
1292:                StringBuffer buf = new StringBuffer(aPath);
1293:                for (Iterator iter = hintClasses.iterator(); iter.hasNext();) {
1294:                    Class hint = (Class) iter.next();
1295:                    buf.append(" ");
1296:                    buf.append(hint.getName());
1297:                }
1298:                return buf.toString();
1299:            }
1300:
1301:            /**
1302:             * Answer the TableAlias for ClassDescriptor.
1303:             */
1304:            protected TableAlias getTableAliasForClassDescriptor(
1305:                    ClassDescriptor aCld) {
1306:                return (TableAlias) m_cldToAlias.get(aCld);
1307:            }
1308:
1309:            /**
1310:             * Set the TableAlias for ClassDescriptor
1311:             */
1312:            private void setTableAliasForClassDescriptor(ClassDescriptor aCld,
1313:                    TableAlias anAlias) {
1314:                if (m_cldToAlias.get(aCld) == null) {
1315:                    m_cldToAlias.put(aCld, anAlias);
1316:                }
1317:            }
1318:
1319:            /**
1320:             * Answer the TableAlias for aPath or aUserAlias
1321:             * @param aPath
1322:             * @param aUserAlias
1323:             * @param hintClasses
1324:             * @return TableAlias, null if none
1325:             */
1326:            private TableAlias getTableAliasForPath(String aPath,
1327:                    String aUserAlias, List hintClasses) {
1328:                if (aUserAlias == null) {
1329:                    return getTableAliasForPath(aPath, hintClasses);
1330:                } else {
1331:                    return getTableAliasForPath(aUserAlias + ALIAS_SEPARATOR
1332:                            + aPath, hintClasses);
1333:                }
1334:            }
1335:
1336:            /**
1337:             * Answer the ClassDescriptor for itemClass for an ObjectReferenceDescriptor
1338:             * check optional hint. The returned Class is to highest superclass contained in the hint list. 
1339:             * TODO: add super ClassDescriptor
1340:             */
1341:            private ClassDescriptor getItemClassDescriptor(
1342:                    ObjectReferenceDescriptor ord, List hintClasses) {
1343:                DescriptorRepository repo = ord.getClassDescriptor()
1344:                        .getRepository();
1345:
1346:                if (hintClasses == null || hintClasses.isEmpty()) {
1347:                    return repo.getDescriptorFor(ord.getItemClass());
1348:                }
1349:
1350:                Class resultClass = (Class) hintClasses.get(0);
1351:
1352:                for (Iterator iter = hintClasses.iterator(); iter.hasNext();) {
1353:                    Class clazz = (Class) iter.next();
1354:                    Class super Clazz = clazz.getSuperclass();
1355:
1356:                    if (super Clazz != null
1357:                            && resultClass.equals(super Clazz.getSuperclass())) {
1358:                        continue; // skip if we already have a super superclass 
1359:                    }
1360:
1361:                    if (hintClasses.contains(super Clazz)) {
1362:                        resultClass = super Clazz; // use superclass if it's in the hints
1363:                    }
1364:                }
1365:
1366:                return repo.getDescriptorFor(resultClass);
1367:            }
1368:
1369:            /**
1370:             * Appends the ORDER BY clause for the Query.
1371:             * <br>
1372:             * If the orderByField is found in the list of selected fields it's index is added. 
1373:             * Otherwise it's name is added.
1374:             * @param orderByFields 
1375:             * @param selectedFields the names of the fields in the SELECT clause
1376:             * @param buf
1377:             */
1378:            protected void appendOrderByClause(List orderByFields,
1379:                    List selectedFields, StringBuffer buf) {
1380:
1381:                if (orderByFields == null || orderByFields.size() == 0) {
1382:                    return;
1383:                }
1384:
1385:                buf.append(" ORDER BY ");
1386:                for (int i = 0; i < orderByFields.size(); i++) {
1387:                    FieldHelper cf = (FieldHelper) orderByFields.get(i);
1388:                    int colNumber = selectedFields.indexOf(cf.name);
1389:
1390:                    if (i > 0) {
1391:                        buf.append(",");
1392:                    }
1393:
1394:                    if (colNumber >= 0) {
1395:                        buf.append(colNumber + 1);
1396:                    } else {
1397:                        appendColName(cf.name, false, null, buf);
1398:                    }
1399:
1400:                    if (!cf.isAscending) {
1401:                        buf.append(" DESC");
1402:                    }
1403:                }
1404:            }
1405:
1406:            /**
1407:             * Appends the GROUP BY clause for the Query
1408:             * @param groupByFields 
1409:             * @param buf
1410:             */
1411:            protected void appendGroupByClause(List groupByFields,
1412:                    StringBuffer buf) {
1413:                if (groupByFields == null || groupByFields.size() == 0) {
1414:                    return;
1415:                }
1416:
1417:                buf.append(" GROUP BY ");
1418:                for (int i = 0; i < groupByFields.size(); i++) {
1419:                    FieldHelper cf = (FieldHelper) groupByFields.get(i);
1420:
1421:                    if (i > 0) {
1422:                        buf.append(",");
1423:                    }
1424:
1425:                    appendColName(cf.name, false, null, buf);
1426:                }
1427:            }
1428:
1429:            /**
1430:             * Appends to the statement table and all tables joined to it.
1431:             * @param alias the table alias
1432:             * @param where append conditions for WHERE clause here
1433:             */
1434:            protected void appendTableWithJoins(TableAlias alias,
1435:                    StringBuffer where, StringBuffer buf) {
1436:                int stmtFromPos = 0;
1437:                byte joinSyntax = getJoinSyntaxType();
1438:
1439:                if (joinSyntax == SQL92_JOIN_SYNTAX) {
1440:                    stmtFromPos = buf.length(); // store position of join (by: Terry Dexter)
1441:                }
1442:
1443:                if (alias == getRoot()) {
1444:                    // BRJ: also add indirection table to FROM-clause for MtoNQuery 
1445:                    if (getQuery() instanceof  MtoNQuery) {
1446:                        MtoNQuery mnQuery = (MtoNQuery) m_query;
1447:                        buf.append(getTableAliasForPath(
1448:                                mnQuery.getIndirectionTable(), null)
1449:                                .getTableAndAlias());
1450:                        buf.append(", ");
1451:                    }
1452:                    buf.append(alias.getTableAndAlias());
1453:                } else if (joinSyntax != SQL92_NOPAREN_JOIN_SYNTAX) {
1454:                    buf.append(alias.getTableAndAlias());
1455:                }
1456:
1457:                if (!alias.hasJoins()) {
1458:                    return;
1459:                }
1460:
1461:                for (Iterator it = alias.iterateJoins(); it.hasNext();) {
1462:                    Join join = (Join) it.next();
1463:
1464:                    if (joinSyntax == SQL92_JOIN_SYNTAX) {
1465:                        appendJoinSQL92(join, where, buf);
1466:                        if (it.hasNext()) {
1467:                            buf.insert(stmtFromPos, "(");
1468:                            buf.append(")");
1469:                        }
1470:                    } else if (joinSyntax == SQL92_NOPAREN_JOIN_SYNTAX) {
1471:                        appendJoinSQL92NoParen(join, where, buf);
1472:                    } else {
1473:                        appendJoin(where, buf, join);
1474:                    }
1475:
1476:                }
1477:            }
1478:
1479:            /**
1480:             * Append Join for non SQL92 Syntax
1481:             */
1482:            private void appendJoin(StringBuffer where, StringBuffer buf,
1483:                    Join join) {
1484:                buf.append(",");
1485:                appendTableWithJoins(join.right, where, buf);
1486:                if (where.length() > 0) {
1487:                    where.append(" AND ");
1488:                }
1489:                join.appendJoinEqualities(where);
1490:            }
1491:
1492:            /**
1493:             * Append Join for SQL92 Syntax
1494:             */
1495:            private void appendJoinSQL92(Join join, StringBuffer where,
1496:                    StringBuffer buf) {
1497:                if (join.isOuter) {
1498:                    buf.append(" LEFT OUTER JOIN ");
1499:                } else {
1500:                    buf.append(" INNER JOIN ");
1501:                }
1502:                if (join.right.hasJoins()) {
1503:                    buf.append("(");
1504:                    appendTableWithJoins(join.right, where, buf);
1505:                    buf.append(")");
1506:                } else {
1507:                    appendTableWithJoins(join.right, where, buf);
1508:                }
1509:                buf.append(" ON ");
1510:                join.appendJoinEqualities(buf);
1511:            }
1512:
1513:            /**
1514:             * Append Join for SQL92 Syntax without parentheses
1515:             */
1516:            private void appendJoinSQL92NoParen(Join join, StringBuffer where,
1517:                    StringBuffer buf) {
1518:                if (join.isOuter) {
1519:                    buf.append(" LEFT OUTER JOIN ");
1520:                } else {
1521:                    buf.append(" INNER JOIN ");
1522:                }
1523:
1524:                buf.append(join.right.getTableAndAlias());
1525:                buf.append(" ON ");
1526:                join.appendJoinEqualities(buf);
1527:
1528:                appendTableWithJoins(join.right, where, buf);
1529:            }
1530:
1531:            /**
1532:             * Build the tree of joins for the given criteria
1533:             */
1534:            private void buildJoinTree(Criteria crit) {
1535:                Enumeration e = crit.getElements();
1536:
1537:                while (e.hasMoreElements()) {
1538:                    Object o = e.nextElement();
1539:                    if (o instanceof  Criteria) {
1540:                        buildJoinTree((Criteria) o);
1541:                    } else {
1542:                        SelectionCriteria c = (SelectionCriteria) o;
1543:
1544:                        // BRJ skip SqlCriteria
1545:                        if (c instanceof  SqlCriteria) {
1546:                            continue;
1547:                        }
1548:
1549:                        // BRJ: Outer join for OR
1550:                        boolean useOuterJoin = (crit.getType() == Criteria.OR);
1551:
1552:                        // BRJ: do not build join tree for subQuery attribute                  
1553:                        if (c.getAttribute() != null
1554:                                && c.getAttribute() instanceof  String) {
1555:                            //buildJoinTreeForColumn((String) c.getAttribute(), useOuterJoin, c.getAlias(), c.getPathClasses());
1556:                            buildJoinTreeForColumn((String) c.getAttribute(),
1557:                                    useOuterJoin, c.getUserAlias(), c
1558:                                            .getPathClasses());
1559:                        }
1560:                        if (c instanceof  FieldCriteria) {
1561:                            FieldCriteria cc = (FieldCriteria) c;
1562:                            buildJoinTreeForColumn((String) cc.getValue(),
1563:                                    useOuterJoin, c.getUserAlias(), c
1564:                                            .getPathClasses());
1565:                        }
1566:                    }
1567:                }
1568:            }
1569:
1570:            /**
1571:             * build the Join-Information for name
1572:             * functions and the last segment are removed
1573:             * ie: avg(accounts.amount) -> accounts
1574:             */
1575:            private void buildJoinTreeForColumn(String aColName,
1576:                    boolean useOuterJoin, UserAlias aUserAlias, Map pathClasses) {
1577:                String pathName = SqlHelper.cleanPath(aColName);
1578:                int sepPos = pathName.lastIndexOf(".");
1579:
1580:                if (sepPos >= 0) {
1581:                    getTableAlias(pathName.substring(0, sepPos), useOuterJoin,
1582:                            aUserAlias, new String[] { pathName
1583:                                    .substring(sepPos + 1) }, pathClasses);
1584:                }
1585:            }
1586:
1587:            /**
1588:             * build the Join-Information if a super reference exists
1589:             *
1590:             * @param left
1591:             * @param cld
1592:             * @param name
1593:             */
1594:            protected void buildSuperJoinTree(TableAlias left,
1595:                    ClassDescriptor cld, String name, boolean useOuterJoin) {
1596:                ClassDescriptor super Cld = cld.getSuperClassDescriptor();
1597:                if (super Cld != null) {
1598:                    SuperReferenceDescriptor super Ref = cld.getSuperReference();
1599:                    FieldDescriptor[] leftFields = super Ref
1600:                            .getForeignKeyFieldDescriptors(cld);
1601:                    TableAlias base_alias = getTableAliasForPath(name, null,
1602:                            null);
1603:                    String aliasName = String.valueOf(getAliasChar())
1604:                            + m_aliasCount++;
1605:                    TableAlias right = new TableAlias(super Cld, aliasName,
1606:                            useOuterJoin, null);
1607:
1608:                    Join join1to1 = new Join(left, leftFields, right, super Cld
1609:                            .getPkFields(), useOuterJoin, "superClass");
1610:                    base_alias.addJoin(join1to1);
1611:
1612:                    buildSuperJoinTree(right, super Cld, name, useOuterJoin);
1613:                }
1614:            }
1615:
1616:            /**
1617:             * build the Join-Information for Subclasses having a super reference to this class
1618:             *
1619:             * @param left
1620:             * @param cld
1621:             * @param name
1622:             */
1623:            private void buildMultiJoinTree(TableAlias left,
1624:                    ClassDescriptor cld, String name, boolean useOuterJoin) {
1625:                DescriptorRepository repository = cld.getRepository();
1626:                Class[] multiJoinedClasses = repository
1627:                        .getSubClassesMultipleJoinedTables(cld, false);
1628:
1629:                for (int i = 0; i < multiJoinedClasses.length; i++) {
1630:                    ClassDescriptor subCld = repository
1631:                            .getDescriptorFor(multiJoinedClasses[i]);
1632:                    SuperReferenceDescriptor srd = subCld.getSuperReference();
1633:                    if (srd != null) {
1634:                        FieldDescriptor[] leftFields = subCld.getPkFields();
1635:                        FieldDescriptor[] rightFields = srd
1636:                                .getForeignKeyFieldDescriptors(subCld);
1637:                        TableAlias base_alias = getTableAliasForPath(name,
1638:                                null, null);
1639:
1640:                        String aliasName = String.valueOf(getAliasChar())
1641:                                + m_aliasCount++;
1642:                        TableAlias right = new TableAlias(subCld, aliasName,
1643:                                false, null);
1644:
1645:                        Join join1to1 = new Join(left, leftFields, right,
1646:                                rightFields, useOuterJoin, "subClass");
1647:                        base_alias.addJoin(join1to1);
1648:
1649:                        buildMultiJoinTree(right, subCld, name, useOuterJoin);
1650:                    }
1651:                }
1652:            }
1653:
1654:            /**
1655:             * First reduce the Criteria to the normal disjunctive form, then
1656:             * calculate the necessary tree of joined tables for each item, then group
1657:             * items with the same tree of joined tables.
1658:             */
1659:            protected void splitCriteria() {
1660:                Criteria whereCrit = getQuery().getCriteria();
1661:                Criteria havingCrit = getQuery().getHavingCriteria();
1662:
1663:                if (whereCrit == null || whereCrit.isEmpty()) {
1664:                    getJoinTreeToCriteria().put(getRoot(), null);
1665:                } else {
1666:                    // TODO: parameters list shold be modified when the form is reduced to DNF.
1667:                    getJoinTreeToCriteria().put(getRoot(), whereCrit);
1668:                    buildJoinTree(whereCrit);
1669:                }
1670:
1671:                if (havingCrit != null && !havingCrit.isEmpty()) {
1672:                    buildJoinTree(havingCrit);
1673:                }
1674:
1675:            }
1676:
1677:            /**
1678:             * Gets the query.
1679:             * @return Returns a Query
1680:             */
1681:            protected QueryByCriteria getQuery() {
1682:                return m_query;
1683:            }
1684:
1685:            /**
1686:             * Gets the root.
1687:             * @return Returns a TableAlias
1688:             */
1689:            protected TableAlias getRoot() {
1690:                return m_root;
1691:            }
1692:
1693:            /**
1694:             * Sets the root.
1695:             * @param root The root to set
1696:             */
1697:            protected void setRoot(TableAlias root) {
1698:                this .m_root = root;
1699:            }
1700:
1701:            /**
1702:             * Gets the search table of this query.
1703:             * @return Returns a TableAlias
1704:             */
1705:            protected TableAlias getSearchTable() {
1706:                return m_search;
1707:            }
1708:
1709:            /**
1710:             * Gets the joinTreeToCriteria.
1711:             * @return Returns a HashMap
1712:             */
1713:            protected HashMap getJoinTreeToCriteria() {
1714:                return m_joinTreeToCriteria;
1715:            }
1716:
1717:            /**
1718:             * Returns the joinSyntaxType.
1719:             * @return byte
1720:             */
1721:            protected byte getJoinSyntaxType() {
1722:                return m_platform.getJoinSyntaxType();
1723:            }
1724:
1725:            /**
1726:             * Returns the logger.
1727:             * @return Logger
1728:             */
1729:            protected Logger getLogger() {
1730:                return m_logger;
1731:            }
1732:
1733:            public String getStatement() {
1734:                if (sql == null) {
1735:                    sql = buildStatement();
1736:                }
1737:                return sql;
1738:            }
1739:
1740:            /**
1741:             * Build the SQL String.
1742:             * @return SQL String
1743:             */
1744:            protected abstract String buildStatement();
1745:
1746:            //-----------------------------------------------------------------
1747:            // ------------------- Inner classes ------------------------------
1748:            //-----------------------------------------------------------------
1749:
1750:            /**
1751:             * This class is a helper to return TableAlias and PathInfo
1752:             */
1753:            static final class AttributeInfo {
1754:                TableAlias tableAlias;
1755:                PathInfo pathInfo;
1756:            }
1757:
1758:            /**
1759:             * This class represents one table (possibly with alias) in the SQL query
1760:             */
1761:            final class TableAlias {
1762:                Logger logger = LoggerFactory.getLogger(TableAlias.class);
1763:                ClassDescriptor cld; // Is null for indirection table of M:N relation
1764:                String table;
1765:                final String alias;
1766:                List extents = new ArrayList();
1767:                List hints = new ArrayList();
1768:                List joins;
1769:
1770:                TableAlias(String aTable, String anAlias) {
1771:                    this .cld = null;
1772:                    this .table = aTable;
1773:                    this .alias = anAlias;
1774:                }
1775:
1776:                TableAlias(ClassDescriptor aCld, String anAlias) {
1777:                    this (aCld, anAlias, false, null);
1778:                }
1779:
1780:                TableAlias(ClassDescriptor aCld, String anAlias,
1781:                        boolean lookForExtents, List hints) {
1782:                    this .cld = aCld;
1783:                    this .table = aCld.getFullTableName();
1784:                    this .alias = anAlias;
1785:                    boolean useHintsOnExtents = false;
1786:
1787:                    // BRJ: store alias map of in enclosing class
1788:                    setTableAliasForClassDescriptor(aCld, this );
1789:
1790:                    //LEANDRO: use hints
1791:                    if (hints != null && hints.size() > 0) {
1792:                        useHintsOnExtents = true;
1793:                    }
1794:
1795:                    logger.debug("TableAlias(): using hints ? "
1796:                            + useHintsOnExtents);
1797:
1798:                    // BRJ : build alias for extents, only one per Table
1799:                    if (lookForExtents) {
1800:                        ClassDescriptor[] extCLDs = (ClassDescriptor[]) aCld
1801:                                .getRepository()
1802:                                .getAllConcreteSubclassDescriptors(aCld)
1803:                                .toArray(new ClassDescriptor[0]);
1804:
1805:                        ClassDescriptor extCd;
1806:                        Class extClass;
1807:                        String extTable;
1808:                        Map extMap = new HashMap(); // only one Alias per Table
1809:                        int firstNonAbstractExtentIndex = 0;
1810:
1811:                        for (int i = 0; i < extCLDs.length; i++) {
1812:                            extCd = extCLDs[i];
1813:                            extClass = extCd.getClassOfObject();
1814:                            if (useHintsOnExtents
1815:                                    && (!hints.contains(extClass))) {
1816:                                //LEANDRO: don't include this class
1817:                                logger.debug("Skipping class [" + extClass
1818:                                        + "] from extents List");
1819:                                firstNonAbstractExtentIndex++;
1820:                                continue;
1821:                            }
1822:                            extTable = extCd.getFullTableName();
1823:
1824:                            // BRJ : Use the first non abstract extent
1825:                            // if the main cld is abstract
1826:                            //logger.debug("cld abstract["+aCld.isAbstract()+"] i["+i+"] index ["+firtsNonAbstractExtentIndex+"]");
1827:                            if (aCld.isAbstract()
1828:                                    && i == firstNonAbstractExtentIndex) {
1829:                                this .cld = extCd;
1830:                                this .table = extTable;
1831:                            } else {
1832:                                // Add a new extent entry only if the table of the extent
1833:                                // does not match the table of the 'base' class.
1834:                                if (extMap.get(extTable) == null
1835:                                        && !extTable.equals(table)) {
1836:                                    extMap.put(extTable, new TableAlias(extCd,
1837:                                            anAlias + "E" + i, false, hints));
1838:                                }
1839:                            }
1840:                        }
1841:                        extents.addAll(extMap.values());
1842:                    }
1843:
1844:                    if (cld == null) {
1845:                        throw new PersistenceBrokerSQLException(
1846:                                "Table is NULL for alias: " + alias);
1847:                    }
1848:                }
1849:
1850:                ClassDescriptor getClassDescriptor() {
1851:                    return cld;
1852:                }
1853:
1854:                String getTableAndAlias() {
1855:                    return table + " " + alias;
1856:                }
1857:
1858:                boolean hasExtents() {
1859:                    return (!extents.isEmpty());
1860:                }
1861:
1862:                Iterator iterateExtents() {
1863:                    return extents.iterator();
1864:                }
1865:
1866:                /**
1867:                 * Copy the Alias and all it's extents adding a Postfix
1868:                 * Joins are not copied.
1869:                 */
1870:                TableAlias copy(String aPostfix) {
1871:                    TableAlias result, temp;
1872:                    Iterator iter = iterateExtents();
1873:
1874:                    if (cld == null) {
1875:                        result = new TableAlias(table, alias + aPostfix);
1876:                    } else {
1877:                        result = new TableAlias(cld, alias + aPostfix);
1878:                    }
1879:
1880:                    while (iter.hasNext()) {
1881:                        temp = (TableAlias) iter.next();
1882:                        result.extents.add(temp.copy(aPostfix));
1883:                    }
1884:
1885:                    return result;
1886:                }
1887:
1888:                void addJoin(Join join) {
1889:                    if (joins == null) {
1890:                        joins = new ArrayList();
1891:                    }
1892:                    joins.add(join);
1893:                }
1894:
1895:                Iterator iterateJoins() {
1896:                    return joins.iterator();
1897:                }
1898:
1899:                boolean hasJoins() {
1900:                    return (joins != null);
1901:                }
1902:
1903:                /**
1904:                 * Get the Join ponting to anAlias.
1905:                 */
1906:                Join getJoin(TableAlias anAlias) {
1907:                    Join result = null;
1908:
1909:                    if (joins != null) {
1910:                        Iterator iter = joins.iterator();
1911:                        while (iter.hasNext()) {
1912:                            Join join = (Join) iter.next();
1913:                            if (join.right.equals(anAlias)) {
1914:                                result = join;
1915:                                break;
1916:                            }
1917:                        }
1918:                    }
1919:                    return result;
1920:                }
1921:
1922:                public String toString() {
1923:                    StringBuffer sb = new StringBuffer(1024);
1924:                    boolean first = true;
1925:
1926:                    sb.append(getTableAndAlias());
1927:                    if (joins != null) {
1928:                        sb.append(" [");
1929:                        for (Iterator it = joins.iterator(); it.hasNext();) {
1930:                            Join join = (Join) it.next();
1931:
1932:                            if (first) {
1933:                                first = false;
1934:                            } else {
1935:                                sb.append(", ");
1936:                            }
1937:                            sb.append("-(");
1938:                            sb.append(join.name);
1939:                            sb.append(")->");
1940:                            sb.append(join.right);
1941:                        }
1942:                        sb.append("]");
1943:                    }
1944:                    return sb.toString();
1945:                }
1946:
1947:                public boolean equals(Object obj) {
1948:                    TableAlias t = (TableAlias) obj;
1949:
1950:                    return table.equals(t.table); // BRJ: check table only
1951:                }
1952:
1953:                public int hashCode() {
1954:                    return table.hashCode();
1955:                }
1956:
1957:            }
1958:
1959:            /**
1960:             * This class represents join between two TableAliases
1961:             */
1962:            final class Join {
1963:                final TableAlias left;
1964:                final String[] leftKeys;
1965:                final TableAlias right;
1966:                final String[] rightKeys;
1967:                boolean isOuter;
1968:                /** This is the name of the field corresponding to this join */
1969:                final String name;
1970:
1971:                /**
1972:                 * leftKeys and rightKeys should be either FieldDescriptor[] or String[]
1973:                 */
1974:                Join(TableAlias left, Object[] leftKeys, TableAlias right,
1975:                        Object[] rightKeys, boolean isOuter, String name) {
1976:                    this .left = left;
1977:                    this .leftKeys = getColumns(leftKeys);
1978:                    this .right = right;
1979:                    this .rightKeys = getColumns(rightKeys);
1980:                    this .isOuter = isOuter;
1981:                    this .name = name;
1982:                }
1983:
1984:                private String[] getColumns(Object[] keys) {
1985:                    String[] columns = new String[keys.length];
1986:
1987:                    if (keys instanceof  FieldDescriptor[]) {
1988:                        FieldDescriptor[] kd = (FieldDescriptor[]) keys;
1989:                        for (int i = 0; i < columns.length; i++) {
1990:                            columns[i] = kd[i].getColumnName();
1991:                        }
1992:                    } else {
1993:                        for (int i = 0; i < columns.length; i++) {
1994:                            columns[i] = keys[i].toString();
1995:                        }
1996:                    }
1997:                    return columns;
1998:                }
1999:
2000:                void appendJoinEqualities(StringBuffer buf) {
2001:                    byte joinSyntax = getJoinSyntaxType();
2002:
2003:                    for (int i = 0; i < leftKeys.length; i++) {
2004:                        if (i > 0) {
2005:                            buf.append(" AND ");
2006:                        }
2007:                        buf.append(left.alias);
2008:                        buf.append(".");
2009:                        buf.append(leftKeys[i]);
2010:
2011:                        if (isOuter && joinSyntax == SYBASE_JOIN_SYNTAX) {
2012:                            buf.append("*=");
2013:                        } else {
2014:                            buf.append("=");
2015:                        }
2016:
2017:                        buf.append(right.alias);
2018:                        buf.append(".");
2019:                        buf.append(rightKeys[i]);
2020:
2021:                        if (isOuter && joinSyntax == ORACLE_JOIN_SYNTAX) {
2022:                            buf.append("(+)");
2023:                        }
2024:                    }
2025:                }
2026:
2027:                public boolean equals(Object obj) {
2028:                    Join j = (Join) obj;
2029:                    return name.equals(j.name) && (isOuter == j.isOuter)
2030:                            && right.equals(j.right);
2031:                }
2032:
2033:                public int hashCode() {
2034:                    return name.hashCode();
2035:                }
2036:
2037:                public String toString() {
2038:                    return left.alias + " -> " + right.alias;
2039:                }
2040:            }
2041:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.