Source Code Cross Referenced for Query.java in  » Development » JoSQL » org » josql » 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 » Development » JoSQL » org.josql 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2004-2007 Gary Bentley 
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may 
0005:         * not use this file except in compliance with the License. 
0006:         * You may obtain a copy of the License at 
0007:         *    http://www.apache.org/licenses/LICENSE-2.0 
0008:         *
0009:         * Unless required by applicable law or agreed to in writing, software 
0010:         * distributed under the License is distributed on an "AS IS" BASIS, 
0011:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0012:         * See the License for the specific language governing permissions and 
0013:         * limitations under the License.
0014:         */
0015:        package org.josql;
0016:
0017:        import java.io.StringReader;
0018:        import java.io.BufferedReader;
0019:
0020:        import java.util.Map;
0021:        import java.util.HashMap;
0022:        import java.util.SortedMap;
0023:        import java.util.LinkedHashMap;
0024:        import java.util.List;
0025:        import java.util.ArrayList;
0026:        import java.util.Iterator;
0027:        import java.util.Collections;
0028:        import java.util.Comparator;
0029:        import java.util.LinkedHashSet;
0030:        import java.util.Collection;
0031:
0032:        import org.josql.parser.JoSQLParser;
0033:
0034:        import org.josql.expressions.*;
0035:
0036:        import org.josql.functions.*;
0037:
0038:        import org.josql.internal.*;
0039:
0040:        import org.josql.events.*;
0041:
0042:        /** 
0043:         * This class provides the ability for a developer to apply an arbitrary SQL statement
0044:         * (using suitable syntax) to a collection of Java objects.
0045:         * <p>
0046:         * Basic usage:
0047:         * <pre>
0048:         *   Query q = new Query ();
0049:         *   q.parse (myStatement);
0050:         *   List results = q.execute (myObjects);
0051:         * </pre>
0052:         * <p>
0053:         * An example statement would look like:
0054:         * <pre>
0055:         *   SELECT lastModified,
0056:         *          name
0057:         *   FROM   java.io.File
0058:         *   WHERE  name LIKE '%.html'
0059:         * </pre>
0060:         * <p>
0061:         * The JoSQL functionality is large and complex, whilst basic queries like the one above are
0062:         * perfectly possible, very complex queries are also possible, for example:
0063:         * <pre>
0064:         *   SELECT name,
0065:         *          formatDate(lastModified),
0066:         *          formatNumber(length),
0067:         *          formatNumber(length - @avg_length),
0068:         *          formatTimeDuration(@max_last_modified - lastModified)
0069:         *   FROM   java.io.File
0070:         *   WHERE  lastModified > @avg_last_modified
0071:         *   AND    length > @avg_length
0072:         *   AND    lower(name) LIKE '%.html'
0073:         *   GROUP BY path
0074:         *   ORDER BY name, lastModified DESC
0075:         *   EXECUTE ON ALL avg (:_allobjs, length) avg_length,
0076:         *                  avg (:_allobjs, lastModified) avg_last_modified,
0077:         *                  max (:_allobjs, lastModified) max_last_modified
0078:         * </pre>
0079:         * <p>
0080:         * Note: the "EXECUTE ON ALL" syntax is an extension used by JoSQL because it has no notion
0081:         * of "aggregate functions".
0082:         * <p>
0083:         * For full details of how a query works and what is possible, see the 
0084:         * <a href="http://josql.sourceforge.net/manual/index.html">JoSQL User Manual</a>.
0085:         * <p>
0086:         * Please note that the package structure for JoSQL is deliberate, JoSQL is designed to be a 
0087:         * black box and lightweight thus only the <code>Query</code> object and associated exceptions
0088:         * are exposed in the main package.  Also, the class structure for JoSQL is not designed to 
0089:         * exactly represent the SQL statement passed to it, rather the classes are optimised for
0090:         * ease of execution of the statement.  If you wish to have a completely accurate Java object
0091:         * view of ANY SQL statement then please see: 
0092:         *   <a href="http://sourceforge.net/projects/jsqlparser">JSqlParser</a>
0093:         * which will provide what you need.
0094:         */
0095:        public class Query {
0096:
0097:            public static String QUERY_BIND_VAR_NAME = "_query";
0098:            public static String PARENT_BIND_VAR_NAME = "_parent";
0099:            public static String CURR_OBJ_VAR_NAME = "_currobj";
0100:            public static String ALL_OBJS_VAR_NAME = "_allobjs";
0101:            public static String GRPBY_OBJ_VAR_NAME = "_grpby";
0102:            public static String GRPBY_OBJ_VAR_NAME_SYNONYM = "_groupby";
0103:            public static final String INT_BIND_VAR_PREFIX = "^^^";
0104:
0105:            public static final String ALL = "ALL";
0106:            public static final String RESULTS = "RESULTS";
0107:            public static final String GROUP_BY_RESULTS = "GROUP_BY_RESULTS";
0108:            public static final String WHERE_RESULTS = "WHERE_RESULTS";
0109:            public static final String HAVING_RESULTS = "HAVING_RESULTS";
0110:
0111:            public static final String ORDER_BY_ASC = "ASC";
0112:            public static final String ORDER_BY_DESC = "DESC";
0113:
0114:            public static final List nullQueryList = new ArrayList();
0115:
0116:            static {
0117:
0118:                Query.nullQueryList.add(new Object());
0119:
0120:            }
0121:
0122:            private List bfhs = new ArrayList();
0123:            private Map bfhsMap = new HashMap();
0124:
0125:            private char wildcardChar = '%';
0126:
0127:            private Map aliases = new HashMap();
0128:            private List groupBys = null;
0129:            private Comparator orderByComp = null;
0130:            private Comparator groupOrderByComp = null;
0131:            private Grouper grouper = null;
0132:            private List orderBys = null;
0133:            private List groupOrderBys = null;
0134:            private List cols = null;
0135:            private boolean retObjs = false;
0136:            private Expression where = null;
0137:            private Expression having = null;
0138:            private Map bindVars = null;
0139:            private String query = null;
0140:            private boolean wantTimings = false;
0141:            private List functionHandlers = null;
0142:            private int anonVarIndex = 1;
0143:            private Expression from = null;
0144:            private Class objClass = null;
0145:            private Limit limit = null;
0146:            private Limit groupByLimit = null;
0147:            private Map executeOn = null;
0148:            private boolean isParsed = false;
0149:            private boolean distinctResults = false;
0150:            private ClassLoader classLoader = null;
0151:            private Query parent = null;
0152:            private Map listeners = new HashMap();
0153:
0154:            // Execution data.
0155:            private transient Object currentObject = null;
0156:            private transient List allObjects = null;
0157:            private transient List currGroupBys = null;
0158:
0159:            private QueryResults qd = null;
0160:
0161:            /**
0162:             * Return the WHERE clause expression.
0163:             *
0164:             * @return The WHERE clause as an expression.
0165:             */
0166:            public Expression getWhereClause() {
0167:
0168:                return this .where;
0169:
0170:            }
0171:
0172:            /**
0173:             * Return the HAVING clause expression.
0174:             *
0175:             * @return The HAVING clause as an expression.
0176:             */
0177:            public Expression getHavingClause() {
0178:
0179:                return this .having;
0180:
0181:            }
0182:
0183:            /**
0184:             * Return the {@link Comparator} we will use to do the ordering of the results, may be null.
0185:             *
0186:             * @return The Comparator.
0187:             */
0188:            public Comparator getOrderByComparator() {
0189:
0190:                return this .orderByComp;
0191:
0192:            }
0193:
0194:            public FunctionHandler getFunctionHandler(String id) {
0195:
0196:                if (this .parent != null) {
0197:
0198:                    return this .parent.getFunctionHandler(id);
0199:
0200:                }
0201:
0202:                return (FunctionHandler) this .bfhsMap.get(id);
0203:
0204:            }
0205:
0206:            private void initFunctionHandlers() {
0207:
0208:                FunctionHandler o = new CollectionFunctions();
0209:                o.setQuery(this );
0210:
0211:                this .bfhsMap.put(CollectionFunctions.HANDLER_ID, o);
0212:
0213:                this .bfhs.add(o);
0214:
0215:                o = new StringFunctions();
0216:                o.setQuery(this );
0217:
0218:                this .bfhsMap.put(StringFunctions.HANDLER_ID, o);
0219:
0220:                this .bfhs.add(o);
0221:
0222:                o = new ConversionFunctions();
0223:                o.setQuery(this );
0224:
0225:                this .bfhsMap.put(ConversionFunctions.HANDLER_ID, o);
0226:
0227:                this .bfhs.add(o);
0228:
0229:                o = new FormattingFunctions();
0230:                o.setQuery(this );
0231:
0232:                this .bfhsMap.put(FormattingFunctions.HANDLER_ID, o);
0233:
0234:                this .bfhs.add(o);
0235:
0236:                o = new GroupingFunctions();
0237:                o.setQuery(this );
0238:
0239:                this .bfhsMap.put(GroupingFunctions.HANDLER_ID, o);
0240:
0241:                this .bfhs.add(o);
0242:
0243:                o = new MiscellaneousFunctions();
0244:                o.setQuery(this );
0245:
0246:                this .bfhsMap.put(MiscellaneousFunctions.HANDLER_ID, o);
0247:
0248:                this .bfhs.add(o);
0249:
0250:            }
0251:
0252:            public Map getExecuteOnFunctions() {
0253:
0254:                return this .executeOn;
0255:
0256:            }
0257:
0258:            public void setExecuteOnFunctions(Map ex) {
0259:
0260:                this .executeOn = ex;
0261:
0262:            }
0263:
0264:            public String getAnonymousBindVariableName() {
0265:
0266:                if (this .parent != null) {
0267:
0268:                    return this .parent.getAnonymousBindVariableName();
0269:
0270:                }
0271:
0272:                String n = Query.INT_BIND_VAR_PREFIX + this .anonVarIndex;
0273:
0274:                this .anonVarIndex++;
0275:
0276:                return n;
0277:
0278:            }
0279:
0280:            public List getDefaultFunctionHandlers() {
0281:
0282:                if (this .parent != null) {
0283:
0284:                    return this .parent.getDefaultFunctionHandlers();
0285:
0286:                }
0287:
0288:                return new ArrayList(this .bfhs);
0289:
0290:            }
0291:
0292:            public List getFunctionHandlers() {
0293:
0294:                if (this .parent != null) {
0295:
0296:                    return this .parent.getFunctionHandlers();
0297:
0298:                }
0299:
0300:                return this .functionHandlers;
0301:
0302:            }
0303:
0304:            public void addFunctionHandler(Object o) {
0305:
0306:                if (this .parent != null) {
0307:
0308:                    this .parent.addFunctionHandler(o);
0309:
0310:                }
0311:
0312:                if (this .functionHandlers == null) {
0313:
0314:                    this .functionHandlers = new ArrayList();
0315:
0316:                }
0317:
0318:                if (o instanceof  FunctionHandler) {
0319:
0320:                    FunctionHandler fh = (FunctionHandler) o;
0321:
0322:                    fh.setQuery(this );
0323:
0324:                }
0325:
0326:                this .functionHandlers.add(o);
0327:
0328:            }
0329:
0330:            public void setFrom(Expression exp) {
0331:
0332:                this .from = exp;
0333:
0334:            }
0335:
0336:            public Expression getFrom() {
0337:
0338:                return this .from;
0339:
0340:            }
0341:
0342:            public void setClassName(String n) {
0343:
0344:                ConstantExpression ce = new ConstantExpression();
0345:                this .from = ce;
0346:                ce.setValue(n);
0347:
0348:            }
0349:
0350:            public void setOrderByColumns(List cols) {
0351:
0352:                this .orderBys = cols;
0353:
0354:            }
0355:
0356:            public void setGroupByLimit(Limit g) {
0357:
0358:                this .groupByLimit = g;
0359:
0360:            }
0361:
0362:            public void setGroupByOrderColumns(List cols) {
0363:
0364:                this .groupOrderBys = cols;
0365:
0366:            }
0367:
0368:            public List getGroupByColumns() {
0369:
0370:                return this .groupBys;
0371:
0372:            }
0373:
0374:            public void setGroupByColumns(List cols) {
0375:
0376:                this .groupBys = cols;
0377:
0378:            }
0379:
0380:            public List getColumns() {
0381:
0382:                return this .cols;
0383:
0384:            }
0385:
0386:            public void setColumns(List cols) {
0387:
0388:                this .cols = cols;
0389:
0390:            }
0391:
0392:            /**
0393:             * Set the expression for the HAVING clause.
0394:             * Caution: do NOT use this method unless you are sure about what you are doing!
0395:             *
0396:             * @param be The expression.
0397:             */
0398:            public void setHaving(Expression be) {
0399:
0400:                this .having = be;
0401:
0402:            }
0403:
0404:            /**
0405:             * Set the expression for the WHERE clause.
0406:             * Caution: do NOT use this method unless you are sure about what you are doing!
0407:             *
0408:             * @param be The expression.
0409:             */
0410:            public void setWhere(Expression be) {
0411:
0412:                this .where = be;
0413:
0414:            }
0415:
0416:            /**
0417:             * Create a new blank Query object.
0418:             */
0419:            public Query() {
0420:
0421:                this .initFunctionHandlers();
0422:
0423:            }
0424:
0425:            public void setWantTimings(boolean v) {
0426:
0427:                this .wantTimings = v;
0428:
0429:            }
0430:
0431:            protected void addTiming(String id, double time) {
0432:
0433:                if (this .wantTimings) {
0434:
0435:                    if (this .qd == null) {
0436:
0437:                        return;
0438:
0439:                    }
0440:
0441:                    if (this .qd.timings == null) {
0442:
0443:                        this .qd.timings = new LinkedHashMap();
0444:
0445:                    }
0446:
0447:                    this .qd.timings.put(id, new Double(time));
0448:
0449:                }
0450:
0451:            }
0452:
0453:            /**
0454:             * Get the value of an indexed bind variable.
0455:             *
0456:             * @param index The index.
0457:             * @return The value.
0458:             */
0459:            public Object getVariable(int index) {
0460:
0461:                if (this .parent != null) {
0462:
0463:                    return this .parent.getVariable(index);
0464:
0465:                }
0466:
0467:                return this .getVariable(Query.INT_BIND_VAR_PREFIX + index);
0468:
0469:            }
0470:
0471:            /**
0472:             * Get the class that the named variable has.
0473:             *
0474:             * @param name The name of the variable.
0475:             * @return The Class.
0476:             */
0477:            public Class getVariableClass(String name) {
0478:
0479:                String n = name.toLowerCase();
0480:
0481:                if (n.equals(Query.QUERY_BIND_VAR_NAME)) {
0482:
0483:                    // Return the query itself!
0484:                    return Query.class;
0485:
0486:                }
0487:
0488:                if (n.equals(Query.PARENT_BIND_VAR_NAME)) {
0489:
0490:                    // Return the query itself!
0491:                    return Query.class;
0492:
0493:                }
0494:
0495:                if (n.equals(Query.CURR_OBJ_VAR_NAME)) {
0496:
0497:                    // May be null if we aren't processing a while/having expression.
0498:                    return this .objClass;
0499:
0500:                }
0501:
0502:                if (n.equals(Query.ALL_OBJS_VAR_NAME)) {
0503:
0504:                    // May change depending upon when it is called.
0505:                    return List.class;
0506:
0507:                }
0508:
0509:                if (this .parent != null) {
0510:
0511:                    return this .parent.getVariableClass(n);
0512:
0513:                }
0514:
0515:                if (this .bindVars == null) {
0516:
0517:                    return Object.class;
0518:
0519:                }
0520:
0521:                Object v = (Object) this .bindVars.get(n);
0522:
0523:                if (v == null) {
0524:
0525:                    return Object.class;
0526:
0527:                }
0528:
0529:                return v.getClass();
0530:
0531:            }
0532:
0533:            /**
0534:             * Get the value of a group by variable from the current group bys.
0535:             *
0536:             * @param ind The variable index.
0537:             * @return The value.
0538:             */
0539:            public Object getGroupByVariable(int ind) {
0540:
0541:                // Get the current group bys.
0542:                if (this .currGroupBys != null) {
0543:
0544:                    return this .currGroupBys.get(ind - 1);
0545:
0546:                }
0547:
0548:                return null;
0549:
0550:            }
0551:
0552:            /**
0553:             * Get the value of a named bind variable.
0554:             *
0555:             * @param name The name of the bind variable.
0556:             * @return The value.
0557:             */
0558:            public Object getVariable(String name) {
0559:
0560:                String n = name.toLowerCase();
0561:
0562:                if (n.startsWith(":")) {
0563:
0564:                    n = n.substring(1);
0565:
0566:                }
0567:
0568:                if (n.equals(Query.QUERY_BIND_VAR_NAME)) {
0569:
0570:                    // Return the query itself!
0571:                    return this ;
0572:
0573:                }
0574:
0575:                if (n.equals(Query.PARENT_BIND_VAR_NAME)) {
0576:
0577:                    // Return the parent query.
0578:                    return this .parent;
0579:
0580:                }
0581:
0582:                if (n.equals(Query.CURR_OBJ_VAR_NAME)) {
0583:
0584:                    // May be null if we aren't processing a while/having expression.
0585:                    return this .currentObject;
0586:
0587:                }
0588:
0589:                if (n.equals(Query.ALL_OBJS_VAR_NAME)) {
0590:
0591:                    // May change depending upon when it is called.
0592:                    return this .allObjects;
0593:
0594:                }
0595:
0596:                if (this .parent != null) {
0597:
0598:                    return this .parent.getVariable(name);
0599:
0600:                }
0601:
0602:                if (this .bindVars == null) {
0603:
0604:                    return null;
0605:
0606:                }
0607:
0608:                return this .bindVars.get(n);
0609:
0610:            }
0611:
0612:            /**
0613:             * Set the value of a named bind variable.
0614:             *
0615:             * @param name The name.
0616:             * @param v The value.
0617:             */
0618:            public void setVariable(String name, Object v) {
0619:
0620:                if (this .parent != null) {
0621:
0622:                    this .parent.setVariable(name, v);
0623:
0624:                    return;
0625:
0626:                }
0627:
0628:                if (this .bindVars == null) {
0629:
0630:                    this .bindVars = new HashMap();
0631:
0632:                }
0633:
0634:                if (name.startsWith(":")) {
0635:
0636:                    name = name.substring(1);
0637:
0638:                }
0639:
0640:                this .bindVars.put(name.toLowerCase(), v);
0641:
0642:            }
0643:
0644:            /**
0645:             * Set the value of an indexed bind variable.
0646:             *
0647:             * @param index The index.
0648:             * @param v The value.
0649:             */
0650:            public void setVariable(int index, Object v) {
0651:
0652:                if (this .parent != null) {
0653:
0654:                    this .parent.setVariable(index, v);
0655:
0656:                    return;
0657:
0658:                }
0659:
0660:                this .setVariable(Query.INT_BIND_VAR_PREFIX + index, v);
0661:
0662:            }
0663:
0664:            /**
0665:             * Get all the bind variables as a Map.
0666:             *
0667:             * @return The name/value mappings of the bind variables.
0668:             */
0669:            public Map getVariables() {
0670:
0671:                if (this .parent != null) {
0672:
0673:                    return this .parent.getVariables();
0674:
0675:                }
0676:
0677:                return this .bindVars;
0678:
0679:            }
0680:
0681:            /**
0682:             * A helper method that will evaluate the WHERE clause for the object passed in.
0683:             *
0684:             * @param o The object to evaluate the WHERE clause against.
0685:             * @return The result of calling: Expression.isTrue(Object,Query) for the WHERE clause.
0686:             */
0687:            public boolean isWhereTrue(Object o) throws QueryExecutionException {
0688:
0689:                if (this .where == null) {
0690:
0691:                    // A null where means yes!
0692:                    return true;
0693:
0694:                }
0695:
0696:                return this .where.isTrue(o, this );
0697:
0698:            }
0699:
0700:            /**
0701:             * Set the bind variables in one go.
0702:             *
0703:             * @param bVars The bind variable name/value mappings.
0704:             */
0705:            public void setVariables(Map bVars) {
0706:
0707:                if (this .parent != null) {
0708:
0709:                    this .parent.setVariables(bVars);
0710:
0711:                    return;
0712:
0713:                }
0714:
0715:                this .bindVars = bVars;
0716:
0717:            }
0718:
0719:            /**
0720:             * Execute all the expressions for the specified type, either: {@link #ALL} or:
0721:             * {@link #RESULTS}.  If the expressions are aliased then the results will be
0722:             * available in the save results upon completion.
0723:             *
0724:             * @param l The List of objects to execute the functions on.
0725:             * @param t The type of expressions to execute.
0726:             * @throws QueryExecutionException If there is an issue with executing one of the
0727:             *                                 expressions or if the Query hasn't been inited yet.
0728:             */
0729:            public void doExecuteOn(List l, String t)
0730:                    throws QueryExecutionException {
0731:
0732:                if (this .executeOn == null) {
0733:
0734:                    // Do nothing.
0735:                    return;
0736:
0737:                }
0738:
0739:                if (!this .isParsed) {
0740:
0741:                    throw new QueryExecutionException(
0742:                            "Query has not been initialised.");
0743:
0744:                }
0745:
0746:                if (this .executeOn != null) {
0747:
0748:                    // Set the "all objects".
0749:                    this .allObjects = l;
0750:
0751:                    long s = System.currentTimeMillis();
0752:
0753:                    List fs = (List) this .executeOn.get(t);
0754:
0755:                    if (fs != null) {
0756:
0757:                        // Execute each one in turn.
0758:                        int si = fs.size();
0759:
0760:                        for (int i = 0; i < si; i++) {
0761:
0762:                            AliasedExpression f = (AliasedExpression) fs.get(i);
0763:
0764:                            Object o = f.getValue(null, this );
0765:
0766:                            String af = f.getAlias();
0767:
0768:                            if (af != null) {
0769:
0770:                                this .setSaveValue(af, o);
0771:
0772:                            }
0773:
0774:                        }
0775:
0776:                        this .addTiming("Total time to execute: " + si
0777:                                + " expression(s) on " + t + " objects", System
0778:                                .currentTimeMillis()
0779:                                - s);
0780:
0781:                    }
0782:
0783:                }
0784:
0785:            }
0786:
0787:            /**
0788:             * This method will be called at the end of a query execution to clean up the
0789:             * transient objects used throughout execution.
0790:             */
0791:            private void clearResults() {
0792:
0793:                this .qd = null;
0794:
0795:                this .currentObject = null;
0796:                this .allObjects = null;
0797:                this .currGroupBys = null;
0798:
0799:            }
0800:
0801:            /**
0802:             * Execute this query on the specified objects.
0803:             *
0804:             * @param objs The list of objects to execute the query on.
0805:             * @return The list of objects that match the query.
0806:             * @throws QueryExecutionException If the query cannot be executed.
0807:             */
0808:            public QueryResults execute(List objs)
0809:                    throws QueryExecutionException {
0810:
0811:                if ((objs == null) && (this .objClass != null)) {
0812:
0813:                    throw new QueryExecutionException(
0814:                            "List of objects must be non-null when an object class is specified.");
0815:
0816:                }
0817:
0818:                this .qd = new QueryResults();
0819:
0820:                if ((this .objClass == null) && (objs == null)) {
0821:
0822:                    objs = Query.nullQueryList;
0823:
0824:                }
0825:
0826:                this .allObjects = objs;
0827:
0828:                // See if we have any expressions that are to be executed on 
0829:                // the complete set.
0830:                this .doExecuteOn(objs, Query.ALL);
0831:
0832:                this .evalWhereClause();
0833:
0834:                // See if we have any functions that are to be executed on 
0835:                // the results...
0836:                this .doExecuteOn(this .qd.results, Query.RESULTS);
0837:
0838:                // If we have a "having" clause execute it here...
0839:                this .evalHavingClause();
0840:
0841:                // Now perform the group by operation.
0842:                if (this .grouper != null) {
0843:
0844:                    this .evalGroupByClause();
0845:
0846:                    return this .qd;
0847:
0848:                }
0849:
0850:                // Now perform the order by.
0851:                this .evalOrderByClause();
0852:
0853:                // Finally, if we have a limit clause, restrict the set of objects returned...
0854:                this .evalLimitClause();
0855:
0856:                this .evalSelectClause();
0857:
0858:                try {
0859:
0860:                    return this .qd;
0861:
0862:                } finally {
0863:
0864:                    // Clean up ;)
0865:                    this .clearResults();
0866:
0867:                }
0868:
0869:            }
0870:
0871:            private void evalSelectClause() throws QueryExecutionException {
0872:
0873:                boolean retNewObjs = false;
0874:
0875:                // See if we are a single column of new objects.
0876:                if (!this .retObjs) {
0877:
0878:                    if (this .cols.size() == 1) {
0879:
0880:                        SelectItemExpression sei = (SelectItemExpression) this .cols
0881:                                .get(0);
0882:
0883:                        if (sei.getExpression() instanceof  NewObjectExpression) {
0884:
0885:                            retNewObjs = true;
0886:
0887:                        }
0888:
0889:                    }
0890:
0891:                }
0892:
0893:                long s = System.currentTimeMillis();
0894:
0895:                // Now get the columns if necessary, we do this here to get the minimum
0896:                // set of objects required.
0897:                if ((!this .retObjs) && (!retNewObjs)) {
0898:
0899:                    Collection resC = null;
0900:
0901:                    if (!this .distinctResults) {
0902:
0903:                        resC = new ArrayList(this .qd.results.size());
0904:
0905:                    } else {
0906:
0907:                        resC = new LinkedHashSet(this .qd.results.size());
0908:
0909:                    }
0910:
0911:                    // Get the column values.
0912:                    this .getColumnValues(this .qd.results, resC);
0913:
0914:                    if (this .distinctResults) {
0915:
0916:                        this .qd.results = new ArrayList(resC);
0917:
0918:                    } else {
0919:
0920:                        this .qd.results = (List) resC;
0921:
0922:                    }
0923:
0924:                    this .addTiming("Collection of results took",
0925:                            (double) (System.currentTimeMillis() - s));
0926:
0927:                } else {
0928:
0929:                    if (this .retObjs) {
0930:
0931:                        if (this .distinctResults) {
0932:
0933:                            s = System.currentTimeMillis();
0934:
0935:                            this .qd.results = ((CollectionFunctions) this 
0936:                                    .getFunctionHandler(CollectionFunctions.HANDLER_ID))
0937:                                    .unique(this .qd.results);
0938:
0939:                            this .addTiming("Collecting unique results took",
0940:                                    (double) (System.currentTimeMillis() - s));
0941:
0942:                        }
0943:
0944:                    }
0945:
0946:                    // If we want a single column of new objects...
0947:                    if (retNewObjs) {
0948:
0949:                        this .qd.results = this 
0950:                                .getNewObjectSingleColumnValues(this .qd.results);
0951:
0952:                    }
0953:
0954:                }
0955:
0956:            }
0957:
0958:            private void evalOrderByClause() throws QueryExecutionException {
0959:
0960:                if ((this .qd.results.size() > 1) && (this .orderByComp != null)) {
0961:
0962:                    long s = System.currentTimeMillis();
0963:
0964:                    // It should be noted here that the comparator will set the
0965:                    // "current object" so that it can be used in the order by
0966:                    // clause.
0967:                    Collections.sort(this .qd.results, this .orderByComp);
0968:
0969:                    this .addTiming("Total time to order results", System
0970:                            .currentTimeMillis()
0971:                            - s);
0972:
0973:                }
0974:
0975:                if (this .orderByComp != null) {
0976:
0977:                    ListExpressionComparator lec = (ListExpressionComparator) this .orderByComp;
0978:
0979:                    if (lec.getException() != null) {
0980:
0981:                        throw new QueryExecutionException(
0982:                                "Unable to order results", lec.getException());
0983:
0984:                    }
0985:
0986:                    lec.clearCache();
0987:
0988:                }
0989:
0990:            }
0991:
0992:            private void evalGroupByClause() throws QueryExecutionException {
0993:
0994:                long s = System.currentTimeMillis();
0995:
0996:                // Need to handle the fact that this will return a Map of Lists...
0997:                try {
0998:
0999:                    s = System.currentTimeMillis();
1000:
1001:                    // Group the objects.
1002:                    Map mres = this .grouper.group(this .qd.results);
1003:
1004:                    this .qd.groupByResults = mres;
1005:
1006:                    List grpBys = new ArrayList(mres.keySet());
1007:
1008:                    // Convert the keys in the group by to a List.
1009:                    Map origSvs = this .qd.saveValues;
1010:
1011:                    Map nres = new LinkedHashMap();
1012:
1013:                    int gs = grpBys.size();
1014:
1015:                    // Now for each "group by" list, do:
1016:                    // 1. Execute the functions for the GROUP_BY_RESULTS type.
1017:                    // 2. Sort the group by results according to the ORDER BY clause.
1018:                    // 3. Limit the group by results according to the LIMIT clause.
1019:                    for (int i = 0; i < gs; i++) {
1020:
1021:                        List l = (List) grpBys.get(i);
1022:
1023:                        List lr = (List) mres.get(l);
1024:
1025:                        this .allObjects = lr;
1026:                        this .currGroupBys = l;
1027:
1028:                        // Now set the save values for the group bys.
1029:                        if (this .qd.groupBySaveValues == null) {
1030:
1031:                            this .qd.groupBySaveValues = new HashMap();
1032:
1033:                        }
1034:
1035:                        this .qd.saveValues = new HashMap();
1036:
1037:                        this .qd.groupBySaveValues.put(l, this .qd.saveValues);
1038:
1039:                        // Now execute all (any) group by results functions.
1040:                        this .doExecuteOn(lr, Query.GROUP_BY_RESULTS);
1041:
1042:                        // Now sort these according to the order by (if any).
1043:                        if ((lr.size() > 1) && (this .orderByComp != null)) {
1044:
1045:                            Collections.sort(lr, this .orderByComp);
1046:
1047:                            ListExpressionComparator lec = (ListExpressionComparator) this .orderByComp;
1048:
1049:                            if (lec.getException() != null) {
1050:
1051:                                throw new QueryExecutionException(
1052:                                        "Unable to order group by results", lec
1053:                                                .getException());
1054:
1055:                            }
1056:
1057:                            lec.clearCache();
1058:
1059:                        }
1060:
1061:                        if (!this .retObjs) {
1062:
1063:                            // Now collect the values...
1064:                            Collection res = null;
1065:
1066:                            if (!this .distinctResults) {
1067:
1068:                                res = new ArrayList();
1069:
1070:                            } else {
1071:
1072:                                res = new LinkedHashSet();
1073:
1074:                            }
1075:
1076:                            this .getColumnValues(lr, res);
1077:
1078:                            if (this .distinctResults) {
1079:
1080:                                lr = new ArrayList(res);
1081:
1082:                            } else {
1083:
1084:                                lr = (List) res;
1085:
1086:                            }
1087:
1088:                        } else {
1089:
1090:                            if (this .distinctResults) {
1091:
1092:                                this .qd.results = ((CollectionFunctions) this 
1093:                                        .getFunctionHandler(CollectionFunctions.HANDLER_ID))
1094:                                        .unique(this .qd.results);
1095:
1096:                            }
1097:
1098:                        }
1099:
1100:                        nres.put(l, lr);
1101:
1102:                    }
1103:
1104:                    // Restore the save values.
1105:                    this .qd.saveValues = origSvs;
1106:
1107:                    // Set the group by results.
1108:                    this .qd.groupByResults = nres;
1109:
1110:                    long t = System.currentTimeMillis();
1111:
1112:                    this .addTiming("Group column collection and sort took",
1113:                            (double) (t - s));
1114:
1115:                    s = t;
1116:
1117:                    // Now order the group bys, if present.
1118:                    if (this .groupOrderByComp != null) {
1119:
1120:                        origSvs = this .qd.saveValues;
1121:
1122:                        Collections.sort(grpBys, this .groupOrderByComp);
1123:
1124:                        // "Restore" the save values.
1125:                        this .qd.saveValues = origSvs;
1126:
1127:                        GroupByExpressionComparator lec = (GroupByExpressionComparator) this .groupOrderByComp;
1128:
1129:                        if (lec.getException() != null) {
1130:
1131:                            throw new QueryExecutionException(
1132:                                    "Unable to order group bys, remember that the current object here is a java.util.List, not the class defined in the FROM clause, you may need to use the org.josq.functions.CollectionFunctions.get(java.util.List,Number) function to get access to the relevant value from the List.",
1133:                                    lec.getException());
1134:
1135:                        }
1136:
1137:                        lec.clearCache();
1138:
1139:                    }
1140:
1141:                    // Now limit the group bys, if required.
1142:                    if (this .groupByLimit != null) {
1143:
1144:                        s = System.currentTimeMillis();
1145:
1146:                        List oGrpBys = grpBys;
1147:
1148:                        grpBys = this .groupByLimit.getSubList(grpBys, this );
1149:
1150:                        // Now trim out from the group by results any list that isn't in the current grpbys.
1151:                        for (int i = 0; i < oGrpBys.size(); i++) {
1152:
1153:                            List l = (List) oGrpBys.get(i);
1154:
1155:                            if (!grpBys.contains(l)) {
1156:
1157:                                // Remove.
1158:                                this .qd.groupByResults.remove(l);
1159:
1160:                            }
1161:
1162:                        }
1163:
1164:                        this .addTiming(
1165:                                "Total time to limit group by results size",
1166:                                System.currentTimeMillis() - s);
1167:
1168:                    }
1169:
1170:                    this .addTiming("Group operation took", (double) (System
1171:                            .currentTimeMillis() - s));
1172:
1173:                    // "Restore" the save values.
1174:                    this .qd.saveValues = origSvs;
1175:
1176:                    this .qd.results = grpBys;
1177:
1178:                    // NOW limit the group by results to a certain size, this needs
1179:                    // to be done last so that the group by limit clause can make use of the size of the
1180:                    // results.
1181:                    if (this .limit != null) {
1182:
1183:                        for (int i = 0; i < this .qd.results.size(); i++) {
1184:
1185:                            List l = (List) this .qd.results.get(i);
1186:
1187:                            List lr = (List) this .qd.groupByResults.get(l);
1188:
1189:                            this .allObjects = lr;
1190:                            this .currGroupBys = l;
1191:
1192:                            this .qd.saveValues = (Map) this .qd.groupBySaveValues
1193:                                    .get(l);
1194:
1195:                            this .qd.groupByResults.put(l, this .limit
1196:                                    .getSubList(lr, this ));
1197:
1198:                        }
1199:
1200:                    }
1201:
1202:                    this .qd.saveValues = origSvs;
1203:
1204:                } catch (Exception e) {
1205:
1206:                    throw new QueryExecutionException(
1207:                            "Unable to perform group by operation", e);
1208:
1209:                }
1210:
1211:            }
1212:
1213:            private void evalHavingClause() throws QueryExecutionException {
1214:
1215:                if (this .having != null) {
1216:
1217:                    int si = this .qd.results.size();
1218:
1219:                    this .qd.havingResults = new ArrayList(si);
1220:
1221:                    for (int i = 0; i < si; i++) {
1222:
1223:                        Object o = this .qd.results.get(i);
1224:
1225:                        this .currentObject = o;
1226:
1227:                        if (this .having.isTrue(o, this )) {
1228:
1229:                            this .qd.havingResults.add(o);
1230:
1231:                        }
1232:
1233:                    }
1234:
1235:                    this .qd.results = this .qd.havingResults;
1236:
1237:                    // Future proofing...
1238:                    this .allObjects = this .qd.results;
1239:
1240:                }
1241:
1242:            }
1243:
1244:            private void evalLimitClause() throws QueryExecutionException {
1245:
1246:                if (this .limit != null) {
1247:
1248:                    long s = System.currentTimeMillis();
1249:
1250:                    this .qd.results = this .limit.getSubList(this .qd.results,
1251:                            this );
1252:
1253:                    this .addTiming("Total time to limit results size", System
1254:                            .currentTimeMillis()
1255:                            - s);
1256:
1257:                }
1258:            }
1259:
1260:            private void evalWhereClause() throws QueryExecutionException {
1261:
1262:                long s = System.currentTimeMillis();
1263:
1264:                int si = this .allObjects.size();
1265:
1266:                if (this .where != null) {
1267:
1268:                    // Create the where results with "about" half the size of the input collection.
1269:                    // Further optimizations may be possible here if some statistics are collected
1270:                    // about how many objects match/fail the where clause and then increase the
1271:                    // capacity of the where results list as required, i.e. to cut down on the number
1272:                    // of array copy and allocation operations performed.  For now though half will do ;)
1273:                    this .qd.whereResults = new ArrayList(si / 2);
1274:
1275:                    for (int i = 0; i < si; i++) {
1276:
1277:                        Object o = this .allObjects.get(i);
1278:
1279:                        this .currentObject = o;
1280:
1281:                        boolean res = this .where.isTrue(o, this );
1282:
1283:                        if (res) {
1284:
1285:                            this .qd.whereResults.add(o);
1286:
1287:                        }
1288:
1289:                    }
1290:
1291:                } else {
1292:
1293:                    // No limiting where clause so what's passed in is what comes out.
1294:                    this .qd.whereResults = this .allObjects;
1295:
1296:                }
1297:
1298:                double wet = (double) System.currentTimeMillis() - (double) s;
1299:
1300:                this .addTiming(
1301:                        "Total time to execute Where clause on all objects",
1302:                        wet);
1303:                this .addTiming("Where took average over: " + si + " objects",
1304:                        wet / (double) si);
1305:
1306:                this .allObjects = this .qd.whereResults;
1307:
1308:                // The results here are the result of executing the where clause, if present.
1309:                this .qd.results = this .qd.whereResults;
1310:
1311:            }
1312:
1313:            public void setCurrentGroupByObjects(List objs) {
1314:
1315:                this .currGroupBys = objs;
1316:
1317:            }
1318:
1319:            /**
1320:             * Get the current list of objects in context (value of the :_allobjs special bind variable).
1321:             * Note: the value of the :_allobjs bind variable will change depending upon where the query execution
1322:             * is up to.
1323:             *
1324:             * @return The list of objects in context.
1325:             */
1326:            public List getAllObjects() {
1327:
1328:                return this .allObjects;
1329:
1330:            }
1331:
1332:            public void setAllObjects(List objs) {
1333:
1334:                this .allObjects = objs;
1335:
1336:            }
1337:
1338:            public void setCurrentObject(Object o) {
1339:
1340:                this .currentObject = o;
1341:
1342:            }
1343:
1344:            /**
1345:             * Get the current object (value of the :_currobj special bind variable).  Note: the value
1346:             * of the :_currobj bind variable will change depending upon where the query execution is up to.
1347:             *
1348:             * @return The current object in context.
1349:             */
1350:            public Object getCurrentObject() {
1351:
1352:                return this .currentObject;
1353:
1354:            }
1355:
1356:            private void getColumnValues(List res, Collection rs)
1357:                    throws QueryExecutionException {
1358:
1359:                int s = res.size();
1360:
1361:                int cs = this .cols.size();
1362:
1363:                boolean addItems = false;
1364:
1365:                for (int i = 0; i < s; i++) {
1366:
1367:                    Object o = res.get(i);
1368:
1369:                    this .currentObject = o;
1370:
1371:                    List sRes = new ArrayList(cs);
1372:
1373:                    for (int j = 0; j < cs; j++) {
1374:
1375:                        SelectItemExpression v = (SelectItemExpression) this .cols
1376:                                .get(j);
1377:
1378:                        try {
1379:
1380:                            if (v.isAddItemsFromCollectionOrMap()) {
1381:
1382:                                addItems = true;
1383:
1384:                            }
1385:
1386:                            // Get the value from the object...
1387:                            Object ov = v.getValue(o, this );
1388:
1389:                            if (addItems) {
1390:
1391:                                rs.addAll(v.getAddItems(ov));
1392:
1393:                            } else {
1394:
1395:                                sRes.add(ov);
1396:
1397:                            }
1398:
1399:                            // Now since the expression can set the current object, put it
1400:                            // back to rights after the call...
1401:                            this .currentObject = o;
1402:
1403:                        } catch (Exception e) {
1404:
1405:                            throw new QueryExecutionException(
1406:                                    "Unable to get value for column: " + j
1407:                                            + " for: " + v.toString()
1408:                                            + " from result: " + i + " (" + o
1409:                                            + ")", e);
1410:
1411:                        }
1412:
1413:                    }
1414:
1415:                    if (!addItems) {
1416:
1417:                        rs.add(sRes);
1418:
1419:                    }
1420:
1421:                }
1422:
1423:            }
1424:
1425:            private List getNewObjectSingleColumnValues(List rows)
1426:                    throws QueryExecutionException {
1427:
1428:                int s = rows.size();
1429:
1430:                SelectItemExpression nsei = (SelectItemExpression) this .cols
1431:                        .get(0);
1432:
1433:                List res = new ArrayList(s);
1434:
1435:                for (int i = 0; i < s; i++) {
1436:
1437:                    Object o = rows.get(i);
1438:
1439:                    this .currentObject = o;
1440:
1441:                    try {
1442:
1443:                        res.add(nsei.getValue(o, this ));
1444:
1445:                        // Now since the expression can set the current object, put it
1446:                        // back to rights after the call...
1447:                        this .currentObject = o;
1448:
1449:                    } catch (Exception e) {
1450:
1451:                        throw new QueryExecutionException(
1452:                                "Unable to get value for column: " + 1
1453:                                        + " for: " + nsei.toString()
1454:                                        + " from result: " + i + " (" + o + ")",
1455:                                e);
1456:
1457:                    }
1458:
1459:                }
1460:
1461:                return res;
1462:
1463:            }
1464:
1465:            public void setSaveValues(Map s) {
1466:
1467:                if (this .parent != null) {
1468:
1469:                    this .parent.qd.saveValues.putAll(s);
1470:
1471:                    return;
1472:
1473:                }
1474:
1475:                this .qd.saveValues = s;
1476:
1477:            }
1478:
1479:            public void setSaveValue(Object id, Object value) {
1480:
1481:                if (this .parent != null) {
1482:
1483:                    this .parent.setSaveValue(id, value);
1484:
1485:                    return;
1486:
1487:                }
1488:
1489:                if (this .qd == null) {
1490:
1491:                    return;
1492:
1493:                }
1494:
1495:                if (id instanceof  String) {
1496:
1497:                    id = ((String) id).toLowerCase();
1498:
1499:                }
1500:
1501:                Object old = this .qd.saveValues.get(id);
1502:
1503:                this .qd.saveValues.put(id, value);
1504:
1505:                if (old != null) {
1506:
1507:                    this .fireSaveValueChangedEvent(id, old, value);
1508:
1509:                }
1510:
1511:            }
1512:
1513:            protected void fireSaveValueChangedEvent(Object id, Object from,
1514:                    Object to) {
1515:
1516:                List l = (List) this .listeners.get("svs");
1517:
1518:                if ((l == null) || (l.size() == 0)) {
1519:
1520:                    return;
1521:
1522:                }
1523:
1524:                SaveValueChangedEvent svce = new SaveValueChangedEvent(this , id
1525:                        .toString().toLowerCase(), from, to);
1526:
1527:                for (int i = 0; i < l.size(); i++) {
1528:
1529:                    SaveValueChangedListener svcl = (SaveValueChangedListener) l
1530:                            .get(i);
1531:
1532:                    svcl.saveValueChanged(svce);
1533:
1534:                }
1535:
1536:            }
1537:
1538:            protected void fireBindVariableChangedEvent(String name,
1539:                    Object from, Object to) {
1540:
1541:                List l = (List) this .listeners.get("bvs");
1542:
1543:                if ((l == null) || (l.size() == 0)) {
1544:
1545:                    return;
1546:
1547:                }
1548:
1549:                BindVariableChangedEvent bvce = new BindVariableChangedEvent(
1550:                        this , name, from, to);
1551:
1552:                for (int i = 0; i < l.size(); i++) {
1553:
1554:                    BindVariableChangedListener bvcl = (BindVariableChangedListener) l
1555:                            .get(i);
1556:
1557:                    bvcl.bindVariableChanged(bvce);
1558:
1559:                }
1560:
1561:            }
1562:
1563:            /**
1564:             * Get the save value for a particular key and group by list.
1565:             *
1566:             * @param id The id of the save value.
1567:             * @param gbs The group by list key.
1568:             * @return The object the key maps to.
1569:             */
1570:            public Object getGroupBySaveValue(Object id, List gbs) {
1571:
1572:                if (this .parent != null) {
1573:
1574:                    return this .getGroupBySaveValue(id, gbs);
1575:
1576:                }
1577:
1578:                Map m = this .getGroupBySaveValues(gbs);
1579:
1580:                if (m == null) {
1581:
1582:                    return null;
1583:
1584:                }
1585:
1586:                return m.get(id);
1587:
1588:            }
1589:
1590:            /**
1591:             * Get the save values for the specified group bys.
1592:             *
1593:             * @param gbs The group bys.
1594:             * @return The save values (name/value pairs).
1595:             */
1596:            public Map getGroupBySaveValues(List gbs) {
1597:
1598:                if (this .parent != null) {
1599:
1600:                    return this .parent.getGroupBySaveValues(gbs);
1601:
1602:                }
1603:
1604:                if ((this .qd == null) || (this .qd.groupBySaveValues == null)) {
1605:
1606:                    return null;
1607:
1608:                }
1609:
1610:                return (Map) this .qd.groupBySaveValues.get(gbs);
1611:
1612:            }
1613:
1614:            /**
1615:             * Get the save values for a particular key.
1616:             *
1617:             * @return The object the key maps to.
1618:             */
1619:            public Object getSaveValue(Object id) {
1620:
1621:                if (this .parent != null) {
1622:
1623:                    return this .parent.getSaveValue(id);
1624:
1625:                }
1626:
1627:                if ((this .qd == null) || (this .qd.saveValues == null)) {
1628:
1629:                    return null;
1630:
1631:                }
1632:
1633:                if (id instanceof  String) {
1634:
1635:                    id = ((String) id).toLowerCase();
1636:
1637:                }
1638:
1639:                return this .qd.saveValues.get(id);
1640:
1641:            }
1642:
1643:            /**
1644:             * Get the query string that this Query object represents.
1645:             *
1646:             * @return The query string.
1647:             */
1648:            public String getQuery() {
1649:
1650:                return this .query;
1651:
1652:            }
1653:
1654:            /**
1655:             * Will cause the order by comparator used to order the results
1656:             * to be initialized.  This is generally only useful if you are specifying the
1657:             * the order bys yourself via: {@link #setOrderByColumns(List)}.  Usage of
1658:             * this method is <b>NOT</b> supported, so don't use unless you really know what 
1659:             * you are doing!
1660:             */
1661:            public void initOrderByComparator() throws QueryParseException {
1662:
1663:                if (this .orderBys != null) {
1664:
1665:                    // No caching, this may need to change in the future.
1666:                    this .orderByComp = new ListExpressionComparator(this , false);
1667:
1668:                    ListExpressionComparator lec = (ListExpressionComparator) this .orderByComp;
1669:
1670:                    // Need to check the type of each order by, if we have
1671:                    // any "column" indexes check to see if they are an accessor...
1672:                    int si = this .orderBys.size();
1673:
1674:                    for (int i = 0; i < si; i++) {
1675:
1676:                        OrderBy ob = (OrderBy) this .orderBys.get(i);
1677:
1678:                        // Get the expression...
1679:                        Expression e = (Expression) ob.getExpression();
1680:
1681:                        if (e == null) {
1682:
1683:                            // Now expect an integer that refers to a column
1684:                            // in the select...
1685:                            int ci = ob.getIndex();
1686:
1687:                            if (ci == 0) {
1688:
1689:                                throw new QueryParseException(
1690:                                        "Order by column indices should start at 1.");
1691:
1692:                            }
1693:
1694:                            if (this .retObjs) {
1695:
1696:                                throw new QueryParseException(
1697:                                        "Cannot sort on a select column index when the objects are to be returned.");
1698:
1699:                            }
1700:
1701:                            if (ci > this .cols.size()) {
1702:
1703:                                throw new QueryParseException(
1704:                                        "Invalid order by column index: "
1705:                                                + ci
1706:                                                + ", only: "
1707:                                                + this .cols.size()
1708:                                                + " columns are selected to be returned.");
1709:
1710:                            }
1711:
1712:                            // Get the SelectItemExpression.
1713:                            SelectItemExpression sei = (SelectItemExpression) this .cols
1714:                                    .get(ci - 1);
1715:
1716:                            // Get the expression...
1717:                            e = sei.getExpression();
1718:
1719:                        } else {
1720:
1721:                            // Init the expression...
1722:                            e.init(this );
1723:
1724:                        }
1725:
1726:                        // Check to see if the expression returns a fixed result, if so
1727:                        // there's no point adding it.
1728:                        if (!e.hasFixedResult(this )) {
1729:
1730:                            lec.addSortItem(e, ob.getType());
1731:
1732:                        }
1733:
1734:                    }
1735:
1736:                }
1737:
1738:            }
1739:
1740:            /**
1741:             * Re-order the objects according to the columns supplied in the <b>dirs</b> Map.
1742:             * The Map should be keyed on an Integer and map to a String value, the String value should
1743:             * be either: {@link #ORDER_BY_ASC} for the column to be in ascending order or: 
1744:             * {@link #ORDER_BY_DESC} for the column to be in descending order.  The Integer refers
1745:             * to a column in the SELECT part of the statement.
1746:             * <p>
1747:             * For example:
1748:             * <p>
1749:             * <pre>
1750:             *   SELECT name,
1751:             *          directory,
1752:             *          file
1753:             *          length
1754:             *   FROM   java.io.File
1755:             * </pre>
1756:             * Can be (re)ordered via the following code:
1757:             * <pre>
1758:             *   Query q = new Query ();
1759:             *   q.parse (sql);
1760:             *   
1761:             *   Map reorderBys = new TreeMap ();
1762:             *   reorderBys.put (new Integer (2), Query.ORDER_BY_ASC);
1763:             *   reorderBys.put (new Integer (3), Query.ORDER_BY_DESC);
1764:             *   reorderBys.put (new Integer (1), Query.ORDER_BY_ASC);
1765:             *   reorderBys.put (new Integer (4), Query.ORDER_BY_DESC);
1766:             *
1767:             *   // Note: this call will cause the entire statement to be executed.
1768:             *   q.reorder (myFiles,
1769:             *              reorderBys);
1770:             * </pre>
1771:             *
1772:             * @param objs The objects you wish to reorder.
1773:             * @param dirs The order bys.
1774:             * @return The QueryResults.
1775:             * @throws QueryParseException If the statement can be parsed, i.e. if any of the order by
1776:             *                             columns is out of range.
1777:             * @throws QueryExecutionException If the call to: {@link #execute(List)} fails.
1778:             * @see #reorder(List,String)
1779:             */
1780:            public QueryResults reorder(List objs, SortedMap dirs)
1781:                    throws QueryExecutionException, QueryParseException {
1782:
1783:                if (this .isWantObjects()) {
1784:
1785:                    throw new QueryParseException(
1786:                            "Only SQL statements that return columns (not the objects passed in) can be re-ordered.");
1787:
1788:                }
1789:
1790:                List obs = new ArrayList();
1791:
1792:                Iterator iter = dirs.keySet().iterator();
1793:
1794:                while (iter.hasNext()) {
1795:
1796:                    Integer in = (Integer) iter.next();
1797:
1798:                    // See if we have a column for it.
1799:                    if (in.intValue() > this .cols.size()) {
1800:
1801:                        throw new QueryParseException("Cannot reorder: "
1802:                                + dirs.size() + " columns, only: "
1803:                                + this .cols.size()
1804:                                + " are present in the SQL statement.");
1805:
1806:                    }
1807:
1808:                    String dir = (String) dirs.get(in);
1809:
1810:                    int d = OrderBy.ASC;
1811:
1812:                    if (dir.equals(Query.ORDER_BY_DESC)) {
1813:
1814:                        d = OrderBy.DESC;
1815:
1816:                    }
1817:
1818:                    OrderBy ob = new OrderBy();
1819:                    ob.setIndex(in.intValue());
1820:                    ob.setType(d);
1821:
1822:                    obs.add(ob);
1823:
1824:                }
1825:
1826:                this .orderBys = obs;
1827:
1828:                this .initOrderByComparator();
1829:
1830:                // Execute the query.
1831:                return this .execute(objs);
1832:
1833:            }
1834:
1835:            /**
1836:             * Allows the re-ordering of the results via a textual representation of the order bys.
1837:             * This is effectively like providing a new ORDER BY clause to the sql.
1838:             * <p>
1839:             * For example:
1840:             * <p>
1841:             * <pre>
1842:             *   SELECT name,
1843:             *          directory,
1844:             *          file
1845:             *          length
1846:             *   FROM   java.io.File
1847:             * </pre>
1848:             * Can be (re)ordered via the following code:
1849:             * <pre>
1850:             *   Query q = new Query ();
1851:             *   q.parse (sql);
1852:             *   
1853:             *   // Note: this call will cause the entire statement to be executed.
1854:             *   q.reorder (myFiles,
1855:             *              "name DESC, 3 ASC, length, 1 DESC");
1856:             * </pre>
1857:             * 
1858:             * @param objs The objects you wish to re-order.
1859:             * @param orderBys The order bys.
1860:             * @return The execution results.
1861:             * @throws QueryParseException If the statement can be parsed, i.e. if any of the order by
1862:             *                             columns is out of range or the order bys cannot be parsed.
1863:             * @throws QueryExecutionException If the call to: {@link #execute(List)} fails.
1864:             * @see #reorder(List,SortedMap)
1865:             */
1866:            public QueryResults reorder(List objs, String orderBys)
1867:                    throws QueryParseException, QueryExecutionException {
1868:
1869:                String sql = "";
1870:
1871:                if (!orderBys.toLowerCase().startsWith("order by")) {
1872:
1873:                    sql = sql + " ORDER BY ";
1874:
1875:                }
1876:
1877:                sql = sql + orderBys;
1878:
1879:                BufferedReader sr = new BufferedReader(new StringReader(sql));
1880:
1881:                JoSQLParser parser = new JoSQLParser(sr);
1882:
1883:                List ors = null;
1884:
1885:                try {
1886:
1887:                    ors = parser.OrderBys();
1888:
1889:                } catch (Exception e) {
1890:
1891:                    throw new QueryParseException("Unable to parse order bys: "
1892:                            + orderBys, e);
1893:
1894:                }
1895:
1896:                this .orderBys = ors;
1897:
1898:                this .initOrderByComparator();
1899:
1900:                // Execute the query.
1901:                return this .execute(objs);
1902:
1903:            }
1904:
1905:            public void setClassLoader(ClassLoader cl) {
1906:
1907:                this .classLoader = cl;
1908:
1909:            }
1910:
1911:            public ClassLoader getClassLoader() {
1912:
1913:                if (this .classLoader == null) {
1914:
1915:                    // No custom classloader specified, use the one that loaded
1916:                    // this class.
1917:                    this .classLoader = Thread.currentThread()
1918:                            .getContextClassLoader();
1919:
1920:                }
1921:
1922:                return this .classLoader;
1923:
1924:            }
1925:
1926:            public Class loadClass(String name) throws Exception {
1927:
1928:                return this .getClassLoader().loadClass(name);
1929:
1930:            }
1931:
1932:            /**
1933:             * Parse the JoSQL query.
1934:             *
1935:             * @param q The query string.
1936:             * @throws QueryParseException If the query cannot be parsed and/or {@link #init() inited}.
1937:             */
1938:            public void parse(String q) throws QueryParseException {
1939:
1940:                this .query = q;
1941:
1942:                BufferedReader sr = new BufferedReader(new StringReader(q));
1943:
1944:                long s = System.currentTimeMillis();
1945:
1946:                JoSQLParser parser = new JoSQLParser(sr);
1947:
1948:                this .addTiming("Time to init josql parser object", System
1949:                        .currentTimeMillis()
1950:                        - s);
1951:
1952:                s = System.currentTimeMillis();
1953:
1954:                try {
1955:
1956:                    parser.parseQuery(this );
1957:
1958:                } catch (Exception e) {
1959:
1960:                    throw new QueryParseException(
1961:                            "Unable to parse query: " + q, e);
1962:
1963:                }
1964:
1965:                this .isParsed = true;
1966:
1967:                this .addTiming("Time to parse query into object form", System
1968:                        .currentTimeMillis()
1969:                        - s);
1970:
1971:                // Init the query.
1972:                this .init();
1973:
1974:            }
1975:
1976:            private void initFromObjectClass() throws QueryParseException {
1977:
1978:                if (this .parent == null) {
1979:
1980:                    if (!(this .from instanceof  ConstantExpression)) {
1981:
1982:                        throw new QueryParseException(
1983:                                "The FROM clause of the outer-most Query must be a string that denotes a fully-qualified class name, expression: "
1984:                                        + this .from + " is not valid.");
1985:
1986:                    }
1987:
1988:                    // See if the class name is the special "null".
1989:                    String cn = null;
1990:
1991:                    try {
1992:
1993:                        // Should be safe to use a null value here (especially since we know
1994:                        // how ConstantExpression works ;)
1995:                        cn = (String) this .from.getValue(null, this );
1996:
1997:                    } catch (Exception e) {
1998:
1999:                        throw new QueryParseException(
2000:                                "Unable to determine FROM clause of the outer-most Query from expression: "
2001:                                        + this .from
2002:                                        + ", note: this exception shouldn't be able to happen, so something has gone SERIOUSLY wrong!",
2003:                                e);
2004:
2005:                    }
2006:
2007:                    if (!cn.equalsIgnoreCase("null")) {
2008:
2009:                        // Load the class that we are dealing with...
2010:                        try {
2011:
2012:                            this .objClass = this .loadClass(cn);
2013:
2014:                        } catch (Exception e) {
2015:
2016:                            throw new QueryParseException(
2017:                                    "Unable to load FROM class: " + cn, e);
2018:
2019:                        }
2020:
2021:                    }
2022:
2023:                }
2024:
2025:            }
2026:
2027:            public void init() throws QueryParseException {
2028:
2029:                long s = System.currentTimeMillis();
2030:
2031:                // If we don't have a parent, then there must be an explicit class name.
2032:                this .initFromObjectClass();
2033:
2034:                // Now if we have any columns, init those as well...
2035:                this .initSelect();
2036:
2037:                // Now init the where clause (where possible)...
2038:                if (this .where != null) {
2039:
2040:                    this .where.init(this );
2041:
2042:                }
2043:
2044:                // Now init the having clause (where possible)...
2045:                if (this .having != null) {
2046:
2047:                    this .having.init(this );
2048:
2049:                }
2050:
2051:                // See if we have order by columns, if so init the comparator.
2052:                this .initOrderByComparator();
2053:
2054:                // See if we have order by columns, if so init the comparator.
2055:                if (this .groupBys != null) {
2056:
2057:                    this .initGroupBys();
2058:
2059:                }
2060:
2061:                this .initGroupOrderBys();
2062:
2063:                if (this .groupByLimit != null) {
2064:
2065:                    this .groupByLimit.init(this );
2066:
2067:                }
2068:
2069:                if (this .limit != null) {
2070:
2071:                    this .limit.init(this );
2072:
2073:                }
2074:
2075:                this .initExecuteOn();
2076:
2077:                this .addTiming("Time to init Query objects", System
2078:                        .currentTimeMillis()
2079:                        - s);
2080:
2081:            }
2082:
2083:            private void initSelect() throws QueryParseException {
2084:
2085:                if (this .retObjs) {
2086:
2087:                    // Nothing to do.
2088:                    return;
2089:
2090:                }
2091:
2092:                int aic = 0;
2093:
2094:                int si = this .cols.size();
2095:
2096:                this .aliases = new HashMap();
2097:
2098:                for (int i = 0; i < si; i++) {
2099:
2100:                    SelectItemExpression exp = (SelectItemExpression) this .cols
2101:                            .get(i);
2102:
2103:                    exp.init(this );
2104:
2105:                    if (exp.isAddItemsFromCollectionOrMap()) {
2106:
2107:                        aic++;
2108:
2109:                    }
2110:
2111:                    String alias = exp.getAlias();
2112:
2113:                    if (alias != null) {
2114:
2115:                        this .aliases.put(alias, Integer.valueOf(i + 1));
2116:
2117:                    }
2118:
2119:                    this .aliases.put((i + 1) + "", Integer.valueOf(i + 1));
2120:
2121:                }
2122:
2123:                if ((aic > 0) && (aic != si)) {
2124:
2125:                    throw new QueryParseException(
2126:                            "If one or more SELECT clause columns is set to add the items returned from a: "
2127:                                    + Map.class.getName()
2128:                                    + " or: "
2129:                                    + java.util.Collection.class.getName()
2130:                                    + " then ALL columns must be marked to return the items as well.");
2131:
2132:                }
2133:
2134:            }
2135:
2136:            private void initGroupBys() throws QueryParseException {
2137:
2138:                this .grouper = new Grouper(this );
2139:
2140:                int si = this .groupBys.size();
2141:
2142:                for (int i = 0; i < si; i++) {
2143:
2144:                    OrderBy ob = (OrderBy) this .groupBys.get(i);
2145:
2146:                    // Get the expression...
2147:                    Expression e = (Expression) ob.getExpression();
2148:
2149:                    if (e == null) {
2150:
2151:                        // Now expect an integer that refers to a column
2152:                        // in the select...
2153:                        int ci = ob.getIndex();
2154:
2155:                        if (ci == 0) {
2156:
2157:                            throw new QueryParseException(
2158:                                    "Order by column indices should start at 1.");
2159:
2160:                        }
2161:
2162:                        if (this .retObjs) {
2163:
2164:                            throw new QueryParseException(
2165:                                    "Cannot sort on a select column index when the objects are to be returned.");
2166:
2167:                        }
2168:
2169:                        if (ci > this .cols.size()) {
2170:
2171:                            throw new QueryParseException(
2172:                                    "Invalid order by column index: "
2173:                                            + ci
2174:                                            + ", only: "
2175:                                            + this .cols.size()
2176:                                            + " columns are selected to be returned.");
2177:
2178:                        }
2179:
2180:                        // Get the SelectItemExpression.
2181:                        SelectItemExpression sei = (SelectItemExpression) this .cols
2182:                                .get(ci - 1);
2183:
2184:                        // Get the expression...
2185:                        e = sei.getExpression();
2186:
2187:                    } else {
2188:
2189:                        // Init the expression...
2190:                        e.init(this );
2191:
2192:                    }
2193:
2194:                    this .grouper.addExpression(e);
2195:
2196:                }
2197:
2198:            }
2199:
2200:            private void initExecuteOn() throws QueryParseException {
2201:
2202:                if (this .executeOn == null) {
2203:
2204:                    return;
2205:
2206:                }
2207:
2208:                // Get the supported types.
2209:                List allF = (List) this .executeOn.get(Query.ALL);
2210:
2211:                if (allF != null) {
2212:
2213:                    // We have some, so init them...
2214:                    int si = allF.size();
2215:
2216:                    for (int i = 0; i < si; i++) {
2217:
2218:                        AliasedExpression f = (AliasedExpression) allF.get(i);
2219:
2220:                        f.init(this );
2221:
2222:                    }
2223:
2224:                }
2225:
2226:                List resultsF = (List) this .executeOn.get(Query.RESULTS);
2227:
2228:                if (resultsF != null) {
2229:
2230:                    // We have some, so init them...
2231:                    int si = resultsF.size();
2232:
2233:                    for (int i = 0; i < si; i++) {
2234:
2235:                        AliasedExpression f = (AliasedExpression) resultsF
2236:                                .get(i);
2237:
2238:                        f.init(this );
2239:
2240:                    }
2241:
2242:                }
2243:
2244:                resultsF = (List) this .executeOn.get(Query.GROUP_BY_RESULTS);
2245:
2246:                if (resultsF != null) {
2247:
2248:                    // We have some, so init them...
2249:                    int si = resultsF.size();
2250:
2251:                    for (int i = 0; i < si; i++) {
2252:
2253:                        AliasedExpression f = (AliasedExpression) resultsF
2254:                                .get(i);
2255:
2256:                        f.init(this );
2257:
2258:                    }
2259:
2260:                }
2261:
2262:            }
2263:
2264:            private void initGroupOrderBys() throws QueryParseException {
2265:
2266:                if (this .groupOrderBys == null) {
2267:
2268:                    // Nothing to do.
2269:                    return;
2270:
2271:                }
2272:
2273:                if (this .grouper == null) {
2274:
2275:                    throw new QueryParseException(
2276:                            "Group Order Bys are only valid if 1 or more Group By columns have been specified.");
2277:
2278:                }
2279:
2280:                // Here we "override" the from class because when dealing with the order bys the
2281:                // current object will be a List, NOT the class defined in the FROM clause.
2282:                Class c = this .objClass;
2283:
2284:                this .objClass = List.class;
2285:
2286:                // No caching, this may need to change in the future.
2287:                this .groupOrderByComp = new GroupByExpressionComparator(this ,
2288:                        false);
2289:
2290:                GroupByExpressionComparator lec = (GroupByExpressionComparator) this .groupOrderByComp;
2291:
2292:                List grouperExps = this .grouper.getExpressions();
2293:
2294:                // Need to check the type of each order by, if we have
2295:                // any "column" indexes check to see if they are an accessor...
2296:                int si = this .groupOrderBys.size();
2297:
2298:                for (int i = 0; i < si; i++) {
2299:
2300:                    OrderBy ob = (OrderBy) this .groupOrderBys.get(i);
2301:
2302:                    if (ob.getIndex() > -1) {
2303:
2304:                        int ci = ob.getIndex();
2305:
2306:                        if (ci == 0) {
2307:
2308:                            throw new QueryParseException(
2309:                                    "Group Order by column indices should start at 1.");
2310:
2311:                        }
2312:
2313:                        if (ci > grouperExps.size()) {
2314:
2315:                            throw new QueryParseException(
2316:                                    "Invalid Group Order By column index: "
2317:                                            + ci
2318:                                            + ", only: "
2319:                                            + grouperExps.size()
2320:                                            + " Group By columns are selected to be returned.");
2321:
2322:                        }
2323:
2324:                        lec.addSortItem(null,
2325:                        // Remember the -1!  Column indices start at 1 but
2326:                                // List indices start at 0 ;)
2327:                                ci - 1, ob.getType());
2328:
2329:                        continue;
2330:
2331:                    }
2332:
2333:                    // Get the expression...
2334:                    Expression e = (Expression) ob.getExpression();
2335:
2336:                    // See if the expression is a "direct" match for any of the
2337:                    // group by columns.
2338:                    boolean cont = true;
2339:
2340:                    for (int j = 0; j < grouperExps.size(); j++) {
2341:
2342:                        Expression exp = (Expression) grouperExps.get(j);
2343:
2344:                        if (e.equals(exp)) {
2345:
2346:                            // This is a match, add to the comparator.
2347:                            lec.addSortItem(null, j, ob.getType());
2348:
2349:                            cont = false;
2350:
2351:                        }
2352:
2353:                    }
2354:
2355:                    if (!cont) {
2356:
2357:                        continue;
2358:
2359:                    }
2360:
2361:                    if ((e instanceof  Function) || (e instanceof  BindVariable)
2362:                            || (e instanceof  SaveValue)) {
2363:
2364:                        e.init(this );
2365:
2366:                        lec.addSortItem(e, -1, ob.getType());
2367:
2368:                        continue;
2369:
2370:                    }
2371:
2372:                    // If we are here then we haven't been able to deal with the 
2373:                    // order by... so barf.
2374:                    throw new QueryParseException(
2375:                            "If the Group Order By: "
2376:                                    + ob
2377:                                    + " is not a function, a bind variable or a save value then it must be present in the Group By list.");
2378:
2379:                }
2380:
2381:                // Restore the FROM object class.
2382:                this .objClass = c;
2383:
2384:            }
2385:
2386:            /**
2387:             * Set the "FROM" object class.  It is advised that you NEVER call this method, do so
2388:             * at your own risk, dragons will swoop from the sky and crisp your innards if you do so!!!
2389:             * Seriously though ;), this method should ONLY be called by those who know what they
2390:             * are doing, whatever you think you know about how this method operates is irrelevant
2391:             * which is why the dangers of calling this method are not documented...  
2392:             * <p>
2393:             * YOU HAVE BEEN WARNED!!!  NO BUGS WILL BE ACCEPTED THAT ARISE FROM THE CALLING OF
2394:             * THIS METHOD!!!
2395:             *
2396:             * @param c The FROM class.
2397:             */
2398:            public void setFromObjectClass(Class c) {
2399:
2400:                this .objClass = c;
2401:
2402:            }
2403:
2404:            public Class getFromObjectClass() {
2405:
2406:                return this .objClass;
2407:
2408:            }
2409:
2410:            public void removeBindVariableChangedListener(
2411:                    BindVariableChangedListener bvl) {
2412:
2413:                List l = (List) this .listeners.get("bvs");
2414:
2415:                if (l == null) {
2416:
2417:                    return;
2418:
2419:                }
2420:
2421:                l.remove(bvl);
2422:
2423:            }
2424:
2425:            public void addBindVariableChangedListener(
2426:                    BindVariableChangedListener bvl) {
2427:
2428:                List l = (List) this .listeners.get("bvs");
2429:
2430:                if (l == null) {
2431:
2432:                    l = new ArrayList();
2433:
2434:                    this .listeners.put("bvs", l);
2435:
2436:                }
2437:
2438:                if (!l.contains(bvl)) {
2439:
2440:                    l.add(bvl);
2441:
2442:                }
2443:
2444:            }
2445:
2446:            public void removeSaveValueChangedListener(
2447:                    SaveValueChangedListener svl) {
2448:
2449:                List l = (List) this .listeners.get("svs");
2450:
2451:                if (l == null) {
2452:
2453:                    return;
2454:
2455:                }
2456:
2457:                l.remove(svl);
2458:
2459:            }
2460:
2461:            public void addSaveValueChangedListener(SaveValueChangedListener svl) {
2462:
2463:                List l = (List) this .listeners.get("svs");
2464:
2465:                if (l == null) {
2466:
2467:                    l = new ArrayList();
2468:
2469:                    this .listeners.put("svs", l);
2470:
2471:                }
2472:
2473:                if (!l.contains(svl)) {
2474:
2475:                    l.add(svl);
2476:
2477:                }
2478:
2479:            }
2480:
2481:            public Map getAliases() {
2482:
2483:                return this .aliases;
2484:
2485:            }
2486:
2487:            /**
2488:             * Return whether the query should return objects.
2489:             *
2490:             * @return <code>true</code> if the query should return objects.
2491:             */
2492:            public boolean isWantObjects() {
2493:
2494:                return this .retObjs;
2495:
2496:            }
2497:
2498:            /**
2499:             * Set whether the query should return objects (use <code>true</code>).
2500:             * Caution: Do NOT use unless you are sure about what you are doing!
2501:             *
2502:             * @param v Set to <code>true</code> to indicate that the query should return objects.
2503:             */
2504:            public void setWantObjects(boolean v) {
2505:
2506:                this .retObjs = v;
2507:
2508:            }
2509:
2510:            /**
2511:             * Get the character that represents a wildcard in LIKE searches.
2512:             *
2513:             * @return The char.
2514:             */
2515:            public char getWildcardCharacter() {
2516:
2517:                return this .wildcardChar;
2518:
2519:            }
2520:
2521:            /**
2522:             * Set the character that represents a wildcard in LIKE searches.
2523:             *
2524:             * @param c The char.
2525:             */
2526:            public void setWildcardCharacter(char c) {
2527:
2528:                this .wildcardChar = c;
2529:
2530:            }
2531:
2532:            /**
2533:             * Set the object that represents the <a href="http://josql.sourceforge.net/limit-clause.html" target="_blank">limit clause</a>.
2534:             * Caution: Do NOT use unless you are sure about what you are doing!
2535:             *
2536:             * @param l The object.
2537:             */
2538:            public void setLimit(Limit l) {
2539:
2540:                this .limit = l;
2541:
2542:            }
2543:
2544:            /**
2545:             * Get the object that represents the <a href="http://josql.sourceforge.net/limit-clause.html" target="_blank">limit clause</a>.
2546:             * 
2547:             * @return The object.
2548:             */
2549:            public Limit getLimit() {
2550:
2551:                return this .limit;
2552:
2553:            }
2554:
2555:            /**
2556:             * Return whether this Query object has had a statement applied to it
2557:             * and has been parsed.
2558:             *
2559:             * @return Whether the query is associated with a statement.
2560:             */
2561:            public boolean parsed() {
2562:
2563:                return this .isParsed;
2564:
2565:            }
2566:
2567:            /**
2568:             * Indicate whether "distinct" results are required.
2569:             *
2570:             * @param v Set to <code>true</code> to make the results distinct.
2571:             */
2572:            public void setWantDistinctResults(boolean v) {
2573:
2574:                this .distinctResults = v;
2575:
2576:            }
2577:
2578:            /**
2579:             * Get the results of {@link #execute(java.util.List) executing} this query.
2580:             *
2581:             * @return The query results.
2582:             */
2583:            public QueryResults getQueryResults() {
2584:
2585:                return this .qd;
2586:
2587:            }
2588:
2589:            /**
2590:             * Get the "order bys".  This will return a List of {@link OrderBy} objects.
2591:             * This is generally only useful when you want to {@link #reorder(List,String)} 
2592:             * the search and wish to get access to the textual representation of the order bys.
2593:             * <p>
2594:             * It is therefore possible to modify the orderbys in place, perhaps by using a different
2595:             * expression or changing the direction (since the objects are not cloned before being
2596:             * returned).  However do so at <b>YOUR OWN RISK</b>.  If you do so, then ensure you
2597:             * call: {@link #setOrderByColumns(List)}, then: {@link #initOrderByComparator()}
2598:             * before re-executing the statement, otherwise nothing will happen!
2599:             *
2600:             * @return The order bys.
2601:             */
2602:            public List getOrderByColumns() {
2603:
2604:                return new ArrayList(this .orderBys);
2605:
2606:            }
2607:
2608:            /**
2609:             * Set the parent query.
2610:             * Caution: Do NOT use unless you are sure about what you are doing!
2611:             *
2612:             * @param q The parent query.
2613:             */
2614:            public void setParent(Query q) {
2615:
2616:                this .parent = q;
2617:
2618:            }
2619:
2620:            /**
2621:             * Get the parent query.
2622:             *
2623:             * @return The query, will be <code>null</code> if there is no parent.
2624:             */
2625:            public Query getParent() {
2626:
2627:                return this .parent;
2628:
2629:            }
2630:
2631:            /**
2632:             * Get the top level query if "this" is a sub-query, the query chain is traversed until
2633:             * the top level query is found, i.e. when {@link #getParent()} returns null.
2634:             *
2635:             * @return The top level query, will be <code>null</code> if there is no parent.
2636:             */
2637:            public Query getTopLevelQuery() {
2638:
2639:                Query q = this ;
2640:                Query par = null;
2641:
2642:                while (true) {
2643:
2644:                    par = q.getParent();
2645:
2646:                    if (par == null) {
2647:
2648:                        break;
2649:
2650:                    }
2651:
2652:                    q = par;
2653:
2654:                }
2655:
2656:                return q;
2657:
2658:            }
2659:
2660:            /**
2661:             * Get a string version of this query suitable for debugging.  This will reconstruct the query
2662:             * based on the objects it holds that represent the various clauses.
2663:             *
2664:             * @return The reconstructed query.
2665:             */
2666:            public String toString() {
2667:
2668:                StringBuffer buf = new StringBuffer("SELECT ");
2669:
2670:                if (this .distinctResults) {
2671:
2672:                    buf.append("DISTINCT ");
2673:
2674:                }
2675:
2676:                if (this .retObjs) {
2677:
2678:                    buf.append("*");
2679:
2680:                } else {
2681:
2682:                    for (int i = 0; i < this .cols.size(); i++) {
2683:
2684:                        buf.append(" ");
2685:                        buf.append(this .cols.get(i));
2686:
2687:                        if (i < (this .cols.size() - 1)) {
2688:
2689:                            buf.append(",");
2690:
2691:                        }
2692:
2693:                    }
2694:
2695:                }
2696:
2697:                buf.append(" FROM ");
2698:                buf.append(this .from);
2699:
2700:                if (this .where != null) {
2701:
2702:                    buf.append(" WHERE ");
2703:
2704:                    buf.append(this.where);
2705:
2706:                }
2707:
2708:                return buf.toString();
2709:
2710:            }
2711:
2712:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.