Source Code Cross Referenced for SelectGroupByVisitor.java in  » Database-ORM » Speedo_1.4.5 » org » objectweb » speedo » query » jdo » parser » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


001:        /**
002:         * Speedo: an implementation of JDO compliant personality on top of JORM generic
003:         * I/O sub-system.
004:         * Copyright (C) 2001-2005 France Telecom R&D
005:         *
006:         * This library is free software; you can redistribute it and/or
007:         * modify it under the terms of the GNU Lesser General Public
008:         * License as published by the Free Software Foundation; either
009:         * version 2 of the License, or (at your option) any later version.
010:         *
011:         * This library is distributed in the hope that it will be useful,
012:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:         * Lesser General Public License for more details.
015:         *
016:         * You should have received a copy of the GNU Lesser General Public
017:         * License along with this library; if not, write to the Free Software
018:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019:         *
020:         *
021:         *
022:         * Authors: S.Chassande-Barrioz.
023:         * Created on 3 fevr. 2005
024:         *
025:         */package org.objectweb.speedo.query.jdo.parser;
026:
027:        import org.objectweb.jorm.api.PMapper;
028:        import org.objectweb.jorm.metainfo.api.ClassRef;
029:        import org.objectweb.jorm.metainfo.api.GenClassRef;
030:        import org.objectweb.jorm.metainfo.api.Reference;
031:        import org.objectweb.jorm.type.api.PType;
032:        import org.objectweb.medor.api.Field;
033:        import org.objectweb.medor.api.MedorException;
034:        import org.objectweb.medor.expression.api.Expression;
035:        import org.objectweb.medor.expression.api.ExpressionException;
036:        import org.objectweb.medor.expression.api.Operator;
037:        import org.objectweb.medor.filter.api.FieldOperand;
038:        import org.objectweb.medor.filter.lib.Avg;
039:        import org.objectweb.medor.filter.lib.BasicFieldOperand;
040:        import org.objectweb.medor.filter.lib.Count;
041:        import org.objectweb.medor.filter.lib.Max;
042:        import org.objectweb.medor.filter.lib.Min;
043:        import org.objectweb.medor.filter.lib.Sum;
044:        import org.objectweb.medor.query.api.PropagatedField;
045:        import org.objectweb.medor.query.api.QueryNode;
046:        import org.objectweb.medor.query.api.QueryTree;
047:        import org.objectweb.medor.query.api.QueryTreeField;
048:        import org.objectweb.medor.query.jorm.lib.ClassExtent;
049:        import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper;
050:        import org.objectweb.medor.query.jorm.lib.PNameField;
051:        import org.objectweb.medor.query.lib.Nest;
052:        import org.objectweb.medor.query.lib.SelectProject;
053:        import org.objectweb.speedo.api.SpeedoException;
054:        import org.objectweb.speedo.mim.api.HomeItf;
055:        import org.objectweb.speedo.query.jdo.JDOQueryDefinitionImpl;
056:        import org.objectweb.speedo.query.jdo.JDOQueryEvalContext;
057:
058:        import java.io.Serializable;
059:        import java.math.BigDecimal;
060:        import java.math.BigInteger;
061:        import java.util.ArrayList;
062:        import java.util.Date;
063:        import java.util.HashMap;
064:        import java.util.List;
065:        import java.util.Map;
066:        import java.util.Stack;
067:        import java.util.StringTokenizer;
068:
069:        /**
070:         * This visitor parses select and group by clauses in order to build the
071:         * projected field of a MEDOR query.
072:         * 
073:         * @author S.Chassande-Barrioz
074:         */
075:        public class SelectGroupByVisitor {
076:
077:            /**
078:             * key word for the count operator
079:             */
080:            private static final String COUNT = "count";
081:
082:            /**
083:             * key word for the sum operator
084:             */
085:            private static final String SUM = "sum";
086:
087:            /**
088:             * key word for the min operator
089:             */
090:            private static final String MIN = "min";
091:
092:            /**
093:             * key word for the max operator
094:             */
095:            private static final String MAX = "max";
096:
097:            /**
098:             * key word for the avg operator
099:             */
100:            private static final String AVG = "avg";
101:
102:            /**
103:             * key word for the distrinct constraint
104:             */
105:            private static final String DISTINCT = "distinct";
106:
107:            /**
108:             * key word for the unique constraint
109:             */
110:            private static final String UNIQUE = "unique";
111:
112:            /**
113:             * list of keywords
114:             */
115:            private static final String[] keywords = new String[] {
116:                    COUNT.toLowerCase(), //0
117:                    COUNT.toUpperCase(), //1
118:                    SUM.toLowerCase(), //2
119:                    SUM.toUpperCase(), //3
120:                    MIN.toLowerCase(), //4
121:                    MIN.toUpperCase(), //5
122:                    MAX.toLowerCase(), //6
123:                    MAX.toUpperCase(), //7
124:                    AVG.toLowerCase(), //8
125:                    AVG.toUpperCase(), //9
126:                    DISTINCT.toLowerCase(), //10
127:                    DISTINCT.toUpperCase(), //11
128:                    "(", //12
129:                    ")", //13
130:                    ",", //14
131:                    "as", //15
132:                    "AS", //16
133:                    UNIQUE.toLowerCase(), //17
134:                    UNIQUE.toUpperCase() //18
135:            };
136:
137:            /**
138:             * Retrieves the String representation of the function identifier
139:             */
140:            private final static String getFunctionAsString(int functionIdx) {
141:                switch (functionIdx / 2) {
142:                case 0:
143:                    return "COUNT";
144:                case 1:
145:                    return "SUM";
146:                case 2:
147:                    return "MIN";
148:                case 3:
149:                    return "MAX";
150:                case 4:
151:                    return "AVG";
152:                default:
153:                    return "UNKNOWN";
154:                }
155:
156:            }
157:
158:            /**
159:             * SelectProjet where the simple (not aggregat operation) selected fields
160:             * must be projected.
161:             */
162:            private QueryNode top;
163:
164:            /**
165:             * The query tree corresponding to the query
166:             */
167:            private QueryTree qt;
168:
169:            /**
170:             * The JORM PMapper permitting to fetch PClassMapping for prefetching
171:             */
172:            private PMapper mapper;
173:
174:            private ClassLoader classloader;
175:
176:            /**
177:             * The visitor of variable used in Speedo for building the query. The
178:             * visitor is used here for building paths of the select. Indeed the select
179:             * clause can contains navigation path.
180:             */
181:            private SpeedoQLVariableVisitor sqvv;
182:
183:            /**
184:             * The QueryEvalContext used in Speedo for evaluate the MEDOR query. During
185:             * the visit of select clause, the algorithm determines if prefetching is
186:             * possible and on which class. If prefetching is possible, the
187:             * PClassMapping of the prefetched class and the pname index are assigned on
188:             * the #qec.
189:             */
190:            private JDOQueryEvalContext qec;
191:
192:            /**
193:             * indicate if a distinct constraint is specified in the select clause This
194:             * field is filled after the call of the parse(String) method.
195:             */
196:            private boolean unique = false;
197:
198:            /**
199:             * indicate if a distinct constraint is specified in the select clause This
200:             * field is filled after the call of the parse(String) method.
201:             */
202:            private boolean distinct = false;
203:
204:            /**
205:             * indicate if the select clause contains aggregat operator(s) This field is
206:             * filled after the call of the parse(String) method.
207:             */
208:            private boolean hasAggregate = false;
209:
210:            /**
211:             * contains the MEDOR object permitting to build the projection part of the
212:             * query. MEDOR object type can be one of the following: - Field : it means
213:             * the selected part is a simple navigation (this, this.a.f1, this.a.myB,
214:             * ...) - Expression: it means the selected part is a calculated field such
215:             * as aggregate function (AVG(this.a.f1), this.f1 + this.f2, ...).
216:             * 
217:             * This field is filled after the call of the parse(String) method.
218:             */
219:            private ArrayList selectfields = new ArrayList();
220:
221:            /**
222:             * contains the alias name (String) of the projected fields. The content of
223:             * this field is linked to the #selectfields field. A null value in the list
224:             * means the corresponding selected fields (same index) has no alias.
225:             * 
226:             * This field is filled after the call of the parse(String) method.
227:             */
228:            private ArrayList aliases = new ArrayList();
229:
230:            /**
231:             * contains the list of grouped fields. The grouped fields are the one used
232:             * in an aggregat operator.
233:             * 
234:             * This field is filled after the call of the parse(String) method.
235:             */
236:            private ArrayList groupedFields = new ArrayList();
237:
238:            /**
239:             * contains the list of fields specified in the group by clause.
240:             * 
241:             * This field is filled after the call of the parse(String) method.
242:             */
243:            private ArrayList groupByFields = new ArrayList();
244:
245:            private ArrayList usedFields = new ArrayList();
246:
247:            private ArrayList selectFieldTypes = new ArrayList();
248:
249:            /**
250:             * @param qt
251:             * @param sp
252:             * @param mapper
253:             * @param sqvv
254:             * @param qd
255:             * @param qec
256:             */
257:            public SelectGroupByVisitor(SelectProject sp, QueryTree qt,
258:                    PMapper mapper, SpeedoQLVariableVisitor sqvv,
259:                    JDOQueryEvalContext qec, ClassLoader classloader) {
260:                super ();
261:                this .qt = qt;
262:                this .top = sp;
263:                this .mapper = mapper;
264:                this .sqvv = sqvv;
265:                this .qec = qec;
266:                this .classloader = classloader;
267:            }
268:
269:            public SelectGroupByVisitor(SelectProject sp, QueryTree qt,
270:                    SpeedoQLVariableVisitor sqvv, ClassLoader classloader) {
271:                this (sp, qt, null, sqvv, null, classloader);
272:            }
273:
274:            public Class[] getSelectFieldTypes() {
275:                return (Class[]) selectFieldTypes
276:                        .toArray(new Class[selectFieldTypes.size()]);
277:            }
278:
279:            /**
280:             * Visit the select and Groupby clause
281:             * @param qd is the definition of the query
282:             */
283:            public void visit(JDOQueryDefinitionImpl qd) throws SpeedoException {
284:                try {
285:                    _visit(qd);
286:                } catch (ExpressionException e) {
287:                    throw new SpeedoException(e);
288:                } catch (MedorException e) {
289:                    throw new SpeedoException(e);
290:                }
291:            }
292:
293:            /**
294:             * Visit the select and Groupby clause
295:             * @param qd is the definition of the query
296:             */
297:            private void _visit(JDOQueryDefinitionImpl qd)
298:                    throws SpeedoException, MedorException, ExpressionException {
299:                String select = qd.getResult();
300:                String groupby = qd.getGrouping();
301:                boolean withPrefetch = qd.withPrefetch();
302:                if (select == null || select.length() == 0) {
303:                    select = "this";
304:                }
305:                parseSelect(select);
306:                parseGroupBy(groupby);
307:
308:                //Prefetching or not
309:                if (!hasAggregate //not aggregation
310:                        && withPrefetch //Prefetching asked
311:                        && selectfields.size() == 1 //only one part in the select
312:                ) {
313:                    addPrefetchField(qd);
314:                }
315:                if (hasAggregate) {
316:                    top = addAggregateNode();
317:                }
318:                top.setDistinct(distinct);
319:                projectFields();
320:                if (qec != null) {
321:                    qec.query = top;
322:                }
323:            }
324:
325:            /**
326:             * Add the prefetch field to the current query tree
327:             * @param qd is the definition of the query
328:             */
329:            private void addPrefetchField(JDOQueryDefinitionImpl qd)
330:                    throws MedorException {
331:                Field f = ((PropagatedField) selectfields.get(0))
332:                        .getOriginFields()[0];
333:                if (f instanceof  PNameField) {
334:                    PNameField pnf = (PNameField) f;
335:                    if (pnf.isClassPName() && !pnf.isInGenClass()) {
336:                        //Add prefeched fields
337:                        ClassExtent ce = (ClassExtent) pnf.getQueryTree();
338:                        String prefetchedClassName = ce.getJormName();
339:                        HomeItf sh = (HomeItf) mapper
340:                                .lookup(prefetchedClassName);
341:                        if (sh.getPrefetchOnQuery()) {
342:                            qec.pcm = sh;
343:                            JormQueryTreeHelper.addPrefetchFields(ce, qt, top,
344:                                    qd.getIncludeSubClasses());
345:                            qec.pnIndex = top.getTupleStructure().getSize() + 1;
346:                        }
347:                    }//else the selected field is a class identifier
348:                } //else the selected field is not an identifier or a reference
349:            }
350:
351:            /**
352:             * @return an aggregate node for aggregate operators. the returned node must
353:             * become the root the query tree.
354:             */
355:            private Nest addAggregateNode() throws SpeedoException,
356:                    MedorException {
357:                Map old2newFields = new HashMap();
358:                //project used fields on the QueryNode #top
359:                for (int i = 0; i < usedFields.size(); i++) {
360:                    QueryTreeField qtf = (QueryTreeField) usedFields.get(i);
361:                    Field newf = top.addPropagatedField(qtf.getName(), qtf
362:                            .getType(), new QueryTreeField[] { qtf });
363:                    old2newFields.put(qtf, newf);
364:                }
365:                //replace the use of old fields in 'grouped' by the new projected
366:                replaceFieldsInList(groupedFields, old2newFields);
367:                //replace the use of old fields in 'groupby' by the new projected
368:                replaceFieldsInList(groupByFields, old2newFields);
369:                //replace the use of old fields in 'selected' by the new projected
370:                replaceFieldsInList(selectfields, old2newFields);
371:                return new Nest((QueryTreeField[]) groupedFields
372:                        .toArray(new QueryTreeField[groupedFields.size()]),
373:                        "grouped_fields", (QueryTreeField[]) groupByFields
374:                                .toArray(new QueryTreeField[groupByFields
375:                                        .size()]), "aggregate_node");
376:                //The nest becomes the top node, selected field will add on it
377:            }
378:
379:            /**
380:             * Projects the fields defined in the select clause on the top node. 
381:             */
382:            private void projectFields() throws SpeedoException,
383:                    MedorException, ExpressionException {
384:                //project field on the #top query node
385:                for (int i = 0; i < selectfields.size(); i++) {
386:                    Object o = selectfields.get(i);
387:                    Field fieldOnTop = null;
388:                    String fieldName = (String) aliases.get(i);
389:                    if (o instanceof  Expression) {
390:                        if (fieldName == null || fieldName.length() == 0) {
391:                            fieldName = "field_" + i;
392:                        }
393:                        Expression e = (Expression) o;
394:                        e.compileExpression();
395:                        fieldOnTop = top.addCalculatedField(fieldName, e
396:                                .getType(), e);
397:                    } else if (o instanceof  Field) {
398:                        Field f = (Field) o;
399:                        if (fieldName == null || fieldName.length() == 0) {
400:                            fieldName = f.getName();
401:                        }
402:                        if (!groupByFields.contains(f) || (top instanceof  Nest)) {
403:                            fieldOnTop = top
404:                                    .addPropagatedField(
405:                                            fieldName,
406:                                            f.getType(),
407:                                            new QueryTreeField[] { (QueryTreeField) f });
408:                        } else {
409:                            String fn = top.getName();
410:                            if (fn == null || fn.length() == 0) {
411:                                fn = "";
412:                            } else {
413:                                fn += ".";
414:                            }
415:                            fn += f.getName();
416:                            fieldOnTop = top.getTupleStructure().getField(fn);
417:                        }
418:                    }
419:                    //Compute the field type
420:                    selectFieldTypes.add(getFieldClass(fieldOnTop));
421:                }
422:            }
423:
424:            /**
425:             * Computes the type of a field.
426:             */
427:            private Class getFieldClass(Field field) throws SpeedoException {
428:                PType ptype = field.getType();
429:                String className = null;
430:                switch (ptype.getTypeCode()) {
431:                case PType.TYPECODE_BIGDECIMAL:
432:                    return BigDecimal.class;
433:                case PType.TYPECODE_BIGINTEGER:
434:                    return BigInteger.class;
435:                case PType.TYPECODE_BOOLEAN:
436:                case PType.TYPECODE_OBJBOOLEAN:
437:                    return Boolean.class;
438:                case PType.TYPECODE_BYTE:
439:                case PType.TYPECODE_OBJBYTE:
440:                    return Byte.class;
441:                case PType.TYPECODE_BYTEARRAY:
442:                    return Byte[].class;
443:                case PType.TYPECODE_CHAR:
444:                case PType.TYPECODE_OBJCHAR:
445:                    return Character.class;
446:                case PType.TYPECODE_CHARARRAY:
447:                    return Character[].class;
448:                case PType.TYPECODE_DATE:
449:                    return Date.class;
450:                case PType.TYPECODE_DOUBLE:
451:                case PType.TYPECODE_OBJDOUBLE:
452:                    return Double.class;
453:                case PType.TYPECODE_FLOAT:
454:                case PType.TYPECODE_OBJFLOAT:
455:                    return Float.class;
456:                case PType.TYPECODE_INT:
457:                case PType.TYPECODE_OBJINT:
458:                    return Integer.class;
459:                case PType.TYPECODE_LONG:
460:                case PType.TYPECODE_OBJLONG:
461:                    return Long.class;
462:                case PType.TYPECODE_SERIALIZED:
463:                    return Serializable.class;
464:                case PType.TYPECODE_SHORT:
465:                case PType.TYPECODE_OBJSHORT:
466:                    return Integer.class;
467:                case PType.TYPECODE_STRING:
468:                    return String.class;
469:
470:                case PType.TYPECODE_REFERENCE:
471:                    if (field instanceof  PropagatedField) {
472:                        Field f = ((PropagatedField) field).getOriginFields()[0];
473:                        if (f instanceof  PNameField) {
474:                            PNameField pnf = (PNameField) f;
475:                            if (pnf.isClassPName()) {
476:                                if (pnf.isInGenClass()) {
477:                                    //identifier of the genclass
478:                                    className = pnf.getGenClassRef()
479:                                            .getGenClassId();
480:                                } else {
481:                                    //identifier of a class
482:                                    className = pnf.getMetaObjectClass()
483:                                            .getFQName();
484:                                }
485:                            } else {
486:                                Reference ref = pnf.getReference();
487:                                if (ref instanceof  ClassRef) {
488:                                    //reference to a class
489:                                    className = ((ClassRef) ref).getMOClass()
490:                                            .getFQName();
491:                                } else if (ref instanceof  GenClassRef) {
492:                                    //reference to a genclass
493:                                    className = ((GenClassRef) ref)
494:                                            .getGenClassId();
495:                                }
496:                            }
497:                        }
498:                    }
499:                    break;
500:                default:
501:                    className = ptype.getJavaName();
502:                }
503:                if (className == null) {
504:                    throw new SpeedoException("Type '" + ptype.getJavaName()
505:                            + "' not found for projected field:"
506:                            + field.getName());
507:                } else {
508:                    try {
509:                        return classloader.loadClass(className);
510:                    } catch (ClassNotFoundException e) {
511:                        throw new SpeedoException("Type '" + className
512:                                + "' not found for projected field:"
513:                                + field.getName(), e);
514:                    }
515:                }
516:            }
517:
518:            /**
519:             * Replaces the list elements by the associated value from the map.
520:             * If an element of the list is an Expression (MEDOR), the use of Fields
521:             * in the Expression is replaced.
522:             * @param list
523:             *            is the list containg elements to replace
524:             * @param old2newElement
525:             *            is the table associating the old element (to replace) to the
526:             *            new element.
527:             */
528:            private void replaceFieldsInList(ArrayList list, Map old2newElement)
529:                    throws SpeedoException {
530:                for (int i = 0; i < list.size(); i++) {
531:                    Object old = list.get(i);
532:                    Object neo = old2newElement.get(old);
533:                    if (neo != null && old != neo) {
534:                        list.set(i, neo);
535:                    } else if (old instanceof  Expression) {
536:                        replaceFieldsInExpression((Expression) old,
537:                                old2newElement);
538:                    }
539:                }
540:            }
541:
542:            /**
543:             * Replaces field usage in expression.
544:             * @param e is the expression to treat
545:             * @param old2newElement 
546:             *            is the table associating the old element (to replace) to the
547:             *            new element.
548:             * @throws SpeedoException
549:             */
550:            private void replaceFieldsInExpression(Expression e,
551:                    Map old2newElement) throws SpeedoException {
552:                if (e instanceof  FieldOperand) {
553:                    FieldOperand fo = (FieldOperand) e;
554:                    Field old = fo.getField();
555:                    Field neo = (Field) old2newElement.get(old);
556:                    if (neo != null && old != neo) {
557:                        ((FieldOperand) e).setField(neo);
558:                    }
559:                } else if (e instanceof  Operator) {
560:                    Operator operator = (Operator) e;
561:                    for (int i = 0; i < operator.getOperandNumber(); i++) {
562:                        replaceFieldsInExpression(operator.getExpression(i),
563:                                old2newElement);
564:                    }
565:                }
566:            }
567:
568:            /**
569:             * Parses a select clause (with or without 'SELECT' keyword).
570:             * 
571:             * @see #selectfields, #aliases, #groupedFields, #distinct, #hasAggregate .
572:             *      It
573:             * @param select
574:             * @throws SpeedoException
575:             */
576:            private void parseSelect(String select) throws SpeedoException {
577:                StringTokenizer st = new StringTokenizer(select, " (,)", true);
578:                Stack stack = new Stack();
579:                while (st.hasMoreTokens()) {
580:                    String token = st.nextToken().trim();
581:                    if (token.length() == 0) {
582:                        continue;
583:                    }
584:                    if (token.equalsIgnoreCase("select")) {
585:                        continue;
586:                    }
587:                    int keywordIdx = isKeyword(token);
588:                    if (keywordIdx < 0) {
589:                        parseFieldExpression(token, stack);
590:                    } else if (keywordIdx < 10) {
591:                        //Aggregate operator
592:                        stack.push(new Integer(keywordIdx));
593:                    } else if (keywordIdx == 10 || keywordIdx == 11) {
594:                        //distinct
595:                        if (stack.size() > 0) {
596:                            //the distinct is used in aggregate operator
597:                            stack.push(new Boolean(true));
598:                        } else {
599:                            distinct = true;
600:                        }
601:                    } else if (keywordIdx == 17 || keywordIdx == 18) {
602:                        //unique
603:                        unique = true;
604:                    } else if (keywordIdx == 14) {
605:                        parseComma(stack);
606:                    } else if (keywordIdx == 12) {
607:                        //(
608:                        stack.push(new Integer(keywordIdx));
609:                    } else if (keywordIdx == 13) {
610:                        //)
611:                        parseRightParenthesis(stack);
612:                    }
613:                }
614:                if (stack.size() == 1) {
615:                    //There is only one element in the select clause
616:                    selectfields.add(stack.pop());
617:                    aliases.add(null);
618:                }
619:            }
620:
621:            private void parseFieldExpression(String token, Stack stack)
622:                    throws SpeedoException {
623:                //field expression
624:                if (token.equals("*")) {
625:                    token = "this";
626:                }
627:                Field f = sqvv.getField(token);
628:                if (!usedFields.contains(f)) {
629:                    usedFields.add(f);
630:                }
631:                stack.push(f);
632:            }
633:
634:            private void parseComma(Stack stack) throws SpeedoException {
635:                if (stack.size() > 0) {
636:                    Object o1 = stack.pop();
637:                    if (stack.size() > 1) {
638:                        //with an alias
639:                        Object o2 = stack.pop();
640:                        if (stack.size() > 2) {
641:                            //not the end of the selected field
642:                            stack.push(o2);
643:                            stack.push(o1);
644:                        } else if (!(o1 instanceof  String)
645:                                || !(o2 instanceof  Expression)) {
646:                            throw new SpeedoException(
647:                                    "Malformed selected field "
648:                                            + (selectfields.size() + 1));
649:                        } else {
650:                            selectfields.add(o2);
651:                            aliases.add(o1);
652:                        }
653:                    } else {
654:                        //without an alias
655:                        selectfields.add(o1);
656:                        aliases.add(null);
657:                    }
658:                } else {
659:                    throw new SpeedoException(
660:                            "Empty definition of the selected field "
661:                                    + (selectfields.size() + 1));
662:                }
663:            }
664:
665:            private void parseRightParenthesis(Stack stack)
666:                    throws SpeedoException {
667:                ArrayList operands = new ArrayList();
668:                boolean isOperand = true;
669:                Integer functionIdx = null;
670:                //pop all operand until the '(' and the function identifier
671:                // (Integer)
672:                boolean distinctOnOperand = false;
673:                do {
674:                    Object o = stack.pop();
675:                    isOperand = !new Integer(12).equals(o);
676:                    if (isOperand) {
677:                        //register the operand
678:                        operands.add(o);
679:                    } else {
680:                        if (stack.peek() instanceof  Boolean) {
681:                            distinctOnOperand = ((Boolean) stack.pop())
682:                                    .booleanValue();
683:                        }
684:                        // fetch the function identifier
685:                        functionIdx = (Integer) stack.pop();
686:                    }
687:                } while (isOperand);
688:                Expression e;
689:                //Verify the operand number
690:                if (functionIdx.intValue() > 0 && functionIdx.intValue() < 10) {
691:                    if (operands.size() != 1) {
692:                        throw new SpeedoException(
693:                                "Bad number of operand for the function "
694:                                        + getFunctionAsString(functionIdx
695:                                                .intValue())
696:                                        + ", expected 1 operand, found "
697:                                        + operands.size());
698:                    }
699:                }
700:                //instanciate the medor Operator corresponding to the function
701:                Object operand = operands.get(0);
702:                if (operand instanceof  Expression) {
703:                    e = (Expression) operand;
704:                } else if (operand instanceof  Field) {
705:                    e = new BasicFieldOperand((Field) operand);
706:                } else {
707:                    throw new SpeedoException("Unexpect operand: " + operand);
708:                }
709:                getFieldsFromExpression(e, groupedFields);
710:                hasAggregate = true;
711:                switch (functionIdx.intValue() / 2) {
712:                case 0:
713:                    e = new Count(e, distinctOnOperand);
714:                    break;
715:                case 1:
716:                    e = new Sum(e, distinctOnOperand);
717:                    break;
718:                case 2:
719:                    e = new Min(e, distinctOnOperand);
720:                    break;
721:                case 3:
722:                    e = new Max(e, distinctOnOperand);
723:                    break;
724:                case 4:
725:                    e = new Avg(e, distinctOnOperand);
726:                    break;
727:                default:
728:                    throw new SpeedoException("Unknown function identifier: "
729:                            + functionIdx.intValue());
730:                }
731:                stack.push(e);
732:            }
733:
734:            /**
735:             * Parses a groupby clause (with or without 'GROUP BY' keyword).
736:             * 
737:             * @see #selectfields, #aliases, #groupedFields, #distinct, #hasAggregate .
738:             *      It
739:             * @param select
740:             * @throws SpeedoException
741:             */
742:            private void parseGroupBy(String groupby) throws SpeedoException {
743:                if (groupby == null || groupby.length() == 0) {
744:                    return;
745:                }
746:                StringTokenizer st = new StringTokenizer(groupby, ",", false);
747:                while (st.hasMoreTokens()) {
748:                    groupByFields.add(sqvv.getField(st.nextToken().trim()));
749:                }
750:                for (int i = 0; i < groupByFields.size(); i++) {
751:                    Field f = (Field) groupByFields.get(i);
752:                    if (!usedFields.contains(f)) {
753:                        usedFields.add(f);
754:                    }
755:                }
756:            }
757:
758:            /**
759:             * Parses an expression and register the list of Fiefd used in the
760:             * expression.
761:             * 
762:             * @param e
763:             *            is the expression to parse
764:             * @param result
765:             *            is the list to fill with Field used in the expression
766:             */
767:            private void getFieldsFromExpression(Expression e, List result) {
768:                if (e instanceof  FieldOperand) {
769:                    Field f = ((FieldOperand) e).getField();
770:                    if (!result.contains(f)) {
771:                        result.add(f);
772:                    }
773:                } else if (e instanceof  Operator) {
774:                    Operator operator = (Operator) e;
775:                    for (int i = 0; i < operator.getOperandNumber(); i++) {
776:                        getFieldsFromExpression(operator.getExpression(i),
777:                                result);
778:                    }
779:                }
780:            }
781:
782:            private int isKeyword(String str) {
783:                if (str == null || str.length() == 0) {
784:                    return -1;
785:                }
786:                for (int i = 0; i < keywords.length; i++) {
787:                    if (keywords[i].equals(str)) {
788:                        return i;
789:                    }
790:                }
791:                return -1;
792:            }
793:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.