Source Code Cross Referenced for QueryParser.java in  » EJB-Server-resin-3.1.5 » resin » com » caucho » amber » query » 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 » EJB Server resin 3.1.5 » resin » com.caucho.amber.query 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003:         *
0004:         * This file is part of Resin(R) Open Source
0005:         *
0006:         * Each copy or derived work must preserve the copyright notice and this
0007:         * notice unmodified.
0008:         *
0009:         * Resin Open Source is free software; you can redistribute it and/or modify
0010:         * it under the terms of the GNU General Public License as published by
0011:         * the Free Software Foundation; either version 2 of the License, or
0012:         * (at your option) any later version.
0013:         *
0014:         * Resin Open Source is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017:         * of NON-INFRINGEMENT.  See the GNU General Public License for more
0018:         * details.
0019:         *
0020:         * You should have received a copy of the GNU General Public License
0021:         * along with Resin Open Source; if not, write to the
0022:         *
0023:         *   Free Software Foundation, Inc.
0024:         *   59 Temple Place, Suite 330
0025:         *   Boston, MA 02111-1307  USA
0026:         *
0027:         * @author Scott Ferguson
0028:         */
0029:
0030:        package com.caucho.amber.query;
0031:
0032:        import com.caucho.amber.AmberException;
0033:        import com.caucho.amber.entity.AmberEntityHome;
0034:        import com.caucho.amber.expr.*;
0035:        import com.caucho.amber.expr.fun.*;
0036:        import com.caucho.amber.manager.AmberPersistenceUnit;
0037:        import com.caucho.amber.table.ForeignColumn;
0038:        import com.caucho.amber.table.LinkColumns;
0039:        import com.caucho.amber.table.Table;
0040:        import com.caucho.amber.type.EntityType;
0041:        import com.caucho.amber.type.RelatedType;
0042:        import com.caucho.amber.type.Type;
0043:        import com.caucho.jdbc.JdbcMetaData;
0044:        import com.caucho.log.Log;
0045:        import com.caucho.util.CharBuffer;
0046:        import com.caucho.util.IntMap;
0047:        import com.caucho.util.L10N;
0048:
0049:        import javax.sql.DataSource;
0050:        import java.sql.Connection;
0051:        import java.sql.ResultSet;
0052:        import java.sql.SQLException;
0053:        import java.sql.Statement;
0054:        import java.util.ArrayList;
0055:        import java.util.HashMap;
0056:        import java.util.Map;
0057:        import java.util.logging.Level;
0058:        import java.util.logging.Logger;
0059:
0060:        /**
0061:         * Contains the parser for EJB 3.0 style queries and stores
0062:         * the parsed expressions.
0063:         */
0064:        public class QueryParser {
0065:            static final Logger log = Log.open(QueryParser.class);
0066:            static final L10N L = new L10N(QueryParser.class);
0067:
0068:            public final static int IDENTIFIER = 128;
0069:            public final static int INTEGER = IDENTIFIER + 1;
0070:            public final static int LONG = INTEGER + 1;
0071:            public final static int DOUBLE = LONG + 1;
0072:            public final static int STRING = DOUBLE + 1;
0073:            public final static int TRUE = STRING + 1;
0074:            public final static int FALSE = TRUE + 1;
0075:            public final static int UNKNOWN = FALSE + 1;
0076:            public final static int MEMBER = UNKNOWN + 1;
0077:            public final static int OF = MEMBER + 1;
0078:            public final static int EMPTY = OF + 1;
0079:            public final static int NULL = EMPTY + 1;
0080:
0081:            public final static int FROM = NULL + 1;
0082:            public final static int IN = FROM + 1;
0083:            public final static int SELECT = IN + 1;
0084:            public final static int UPDATE = SELECT + 1;
0085:            public final static int DELETE = UPDATE + 1;
0086:            public final static int DISTINCT = DELETE + 1;
0087:            public final static int WHERE = DISTINCT + 1;
0088:            public final static int AS = WHERE + 1;
0089:            public final static int SET = AS + 1;
0090:            public final static int ORDER = SET + 1;
0091:            public final static int GROUP = ORDER + 1;
0092:            public final static int BY = GROUP + 1;
0093:            public final static int ASC = BY + 1;
0094:            public final static int DESC = ASC + 1;
0095:            public final static int LIMIT = DESC + 1;
0096:            public final static int OFFSET = LIMIT + 1;
0097:
0098:            public final static int JOIN = OFFSET + 1;
0099:            public final static int INNER = JOIN + 1;
0100:            public final static int LEFT = INNER + 1;
0101:            public final static int OUTER = LEFT + 1;
0102:            public final static int FETCH = OUTER + 1;
0103:
0104:            public final static int BETWEEN = FETCH + 1;
0105:            public final static int LIKE = BETWEEN + 1;
0106:            public final static int ESCAPE = LIKE + 1;
0107:            public final static int IS = ESCAPE + 1;
0108:
0109:            public final static int CONCAT_OP = IS + 1;
0110:
0111:            public final static int EQ = CONCAT_OP + 1;
0112:            public final static int NE = EQ + 1;
0113:            public final static int LT = NE + 1;
0114:            public final static int LE = LT + 1;
0115:            public final static int GT = LE + 1;
0116:            public final static int GE = GT + 1;
0117:
0118:            public final static int AND = GE + 1;
0119:            public final static int OR = AND + 1;
0120:            public final static int NOT = OR + 1;
0121:
0122:            public final static int LENGTH = NOT + 1;
0123:            public final static int LOCATE = LENGTH + 1;
0124:
0125:            public final static int ABS = LOCATE + 1;
0126:            public final static int SQRT = ABS + 1;
0127:            public final static int MOD = SQRT + 1;
0128:            public final static int SIZE = MOD + 1;
0129:
0130:            public final static int MAX = SIZE + 1;
0131:            public final static int MIN = MAX + 1;
0132:            public final static int SUM = MIN + 1;
0133:
0134:            public final static int CONCAT = SUM + 1;
0135:            public final static int LOWER = CONCAT + 1;
0136:            public final static int UPPER = LOWER + 1;
0137:            public final static int SUBSTRING = UPPER + 1;
0138:            public final static int TRIM = SUBSTRING + 1;
0139:
0140:            public final static int BOTH = TRIM + 1;
0141:            public final static int LEADING = BOTH + 1;
0142:            public final static int TRAILING = LEADING + 1;
0143:
0144:            public final static int CURRENT_DATE = TRAILING + 1;
0145:            public final static int CURRENT_TIME = CURRENT_DATE + 1;
0146:            public final static int CURRENT_TIMESTAMP = CURRENT_TIME + 1;
0147:
0148:            public final static int EXTERNAL_DOT = CURRENT_TIMESTAMP + 1;
0149:
0150:            public final static int ARG = EXTERNAL_DOT + 1;
0151:            public final static int NAMED_ARG = ARG + 1;
0152:
0153:            public final static int NEW = NAMED_ARG + 1;
0154:
0155:            public final static int THIS = NEW + 1;
0156:
0157:            public final static int NOT_NULL = THIS + 1;
0158:
0159:            public final static int HAVING = NOT_NULL + 1;
0160:
0161:            private static IntMap _reserved;
0162:
0163:            private AmberPersistenceUnit _persistenceUnit;
0164:
0165:            // The query
0166:            private String _sql;
0167:
0168:            /*
0169:            // list of the relation links
0170:            private ArrayList<LinkItem> _linkList;
0171:            // select expression
0172:            private Expr _selectExpr;
0173:            // is distinct (set)
0174:            private boolean _isDistinct;
0175:             */
0176:
0177:            // True if entities should be lazily loaded
0178:            private boolean _isLazyResult;
0179:
0180:            // The select query
0181:            private AbstractQuery _query;
0182:
0183:            // list of relations
0184:            private HashMap<PathExpr, PathExpr> _pathMap = new HashMap<PathExpr, PathExpr>();
0185:
0186:            // parse index
0187:            private int _parseIndex;
0188:            // current token
0189:            private int _token;
0190:            // unique
0191:            private int _unique;
0192:            // parameter count
0193:            private int _parameterCount;
0194:            // temp for parsing
0195:            private String _lexeme;
0196:
0197:            private ArrayList<ArgExpr> _argList = new ArrayList<ArgExpr>();
0198:
0199:            private HashMap<AmberExpr, String> _joinFetchMap;
0200:
0201:            ArrayList<AmberExpr> _groupList = null;
0202:
0203:            private int _sqlArgCount;
0204:
0205:            private FromItem.JoinSemantics _joinSemantics = FromItem.JoinSemantics.UNKNOWN;
0206:
0207:            private boolean _isJoinFetch = false;
0208:
0209:            // Parsing control variable, jpa/0tp4 (TRIM FROM)
0210:            // SELECT .._depth=0.. TRIM(.._depth=1.. 'a' FROM o.d1) .._depth=0 FROM ...
0211:            private int _depth = 0;
0212:
0213:            private boolean _parsingResult;
0214:            private boolean _parsingFrom;
0215:            private boolean _parsingHaving;
0216:
0217:            // jpa/119l: WHERE SIZE(xxx) > 0 => GROUP BY ... HAVING COUNT(xxx) > 0
0218:            private boolean _isSizeFunExpr;
0219:            private AmberExpr _havingExpr;
0220:            // jpa/1199
0221:            ArrayList<AmberExpr> _appendResultList = null;
0222:
0223:            private boolean _isDerbyDBMS;
0224:            private boolean _isPostgresDBMS;
0225:
0226:            /**
0227:             * Creates the query parser.
0228:             */
0229:            public QueryParser(String query) {
0230:                _sql = query;
0231:            }
0232:
0233:            /**
0234:             * Returns true for Derby-like DBMS.
0235:             */
0236:            public boolean isDerbyDBMS() {
0237:                return _isDerbyDBMS;
0238:            }
0239:
0240:            /**
0241:             * Returns true for Postgres-like DBMS.
0242:             */
0243:            public boolean isPostgresDBMS() {
0244:                return _isPostgresDBMS;
0245:            }
0246:
0247:            /**
0248:             * Sets the persistence unit.
0249:             */
0250:            public void setPersistenceUnit(AmberPersistenceUnit persistenceUnit) {
0251:                _persistenceUnit = persistenceUnit;
0252:
0253:                _isDerbyDBMS = false;
0254:                _isPostgresDBMS = false;
0255:
0256:                if (persistenceUnit == null)
0257:                    return;
0258:
0259:                _isDerbyDBMS = !persistenceUnit.hasPositionFunction();
0260:                _isPostgresDBMS = persistenceUnit.getFalseLiteral()
0261:                        .equalsIgnoreCase("false");
0262:            }
0263:
0264:            /**
0265:             * Sets true for lazy loading.
0266:             */
0267:            public void setLazyResult(boolean isLazy) {
0268:                _isLazyResult = isLazy;
0269:            }
0270:
0271:            /**
0272:             * Returns the query string
0273:             */
0274:            public String getQuery() {
0275:                return _sql;
0276:            }
0277:
0278:            /**
0279:             * Returns the query string
0280:             */
0281:            public AbstractQuery getSelectQuery() {
0282:                return _query;
0283:            }
0284:
0285:            /**
0286:             * Initialize the parse.
0287:             */
0288:            private void init() {
0289:                _parseIndex = 0;
0290:                _unique = 0;
0291:                _token = -1;
0292:                _depth = 0;
0293:                _parsingResult = false;
0294:                _parsingFrom = false;
0295:                _parsingHaving = false;
0296:                _havingExpr = null;
0297:                _appendResultList = null;
0298:                _groupList = null;
0299:                _joinFetchMap = new HashMap<AmberExpr, String>();
0300:            }
0301:
0302:            /**
0303:             * Generates a new arg.
0304:             */
0305:            public int generateSQLArg() {
0306:                return _sqlArgCount++;
0307:            }
0308:
0309:            /**
0310:             * Parses the query.
0311:             */
0312:            public AbstractQuery parse() throws AmberException {
0313:                /*
0314:                  _query = query;
0315:                  _fromList = new ArrayList<FromItem>();
0316:                  _pathMap = new HashMap<Expr,Expr>();
0317:                  _idMap = new HashMap<String,PathExpr>();
0318:                  _argList = new ArrayList<Expr>();
0319:                  _linkList = new ArrayList<LinkItem>();
0320:                 */
0321:
0322:                init();
0323:
0324:                int token = scanToken();
0325:                if (token == UPDATE)
0326:                    return parseUpdate();
0327:                else if (token == DELETE)
0328:                    return parseDelete();
0329:
0330:                _token = token;
0331:                return parseSelect(false);
0332:            }
0333:
0334:            private SelectQuery parseSelect(boolean innerSelect)
0335:                    throws QueryParseException {
0336:                int oldParseIndex = _parseIndex;
0337:                int oldToken = _token;
0338:                FromItem.JoinSemantics oldJoinSemantics = _joinSemantics;
0339:                boolean oldIsJoinFetch = _isJoinFetch;
0340:                AbstractQuery oldQuery = _query;
0341:                int oldDepth = _depth;
0342:                AmberExpr oldHavingExpr = _havingExpr;
0343:                ArrayList oldAppendResultList = _appendResultList;
0344:
0345:                // Reset depth: subselect
0346:                _depth = 0;
0347:
0348:                _havingExpr = null;
0349:                _appendResultList = null;
0350:
0351:                SelectQuery query = new SelectQuery(_sql, getMetaData());
0352:                query.setParentQuery(_query);
0353:                _query = query;
0354:
0355:                int token;
0356:                while ((token = scanToken()) >= 0
0357:                        && ((token != FROM) || (_depth > 0))) {
0358:                }
0359:
0360:                // "SELECT CURRENT_DATE" does NOT have a FROM clause.
0361:                boolean hasFrom = (token == FROM);
0362:
0363:                _token = token;
0364:
0365:                if (hasFrom) {
0366:
0367:                    _parsingFrom = true;
0368:
0369:                    do {
0370:
0371:                        scanToken();
0372:
0373:                        _isJoinFetch = false;
0374:
0375:                        if (token == JOIN) {
0376:                            if ((token = peekToken()) == FETCH) {
0377:                                scanToken();
0378:                                _isJoinFetch = true;
0379:                            }
0380:                        }
0381:
0382:                        FromItem from = parseFrom();
0383:
0384:                        token = peekToken();
0385:
0386:                        _joinSemantics = FromItem.JoinSemantics.UNKNOWN;
0387:
0388:                        if (token == INNER) {
0389:                            scanToken();
0390:
0391:                            token = peekToken();
0392:
0393:                            if (token != JOIN) {
0394:                                throw error(L.l("expected JOIN at {0}",
0395:                                        tokenName(token)));
0396:                            }
0397:
0398:                            _joinSemantics = FromItem.JoinSemantics.INNER;
0399:                        } else if (token == LEFT) {
0400:                            scanToken();
0401:
0402:                            token = peekToken();
0403:
0404:                            if (token == OUTER) {
0405:                                scanToken();
0406:
0407:                                token = peekToken();
0408:                            }
0409:
0410:                            if (token != JOIN)
0411:                                throw error(L.l("expected JOIN at {0}",
0412:                                        tokenName(token)));
0413:
0414:                            _joinSemantics = FromItem.JoinSemantics.OUTER;
0415:                        } else if (token == JOIN) {
0416:                            _joinSemantics = FromItem.JoinSemantics.INNER;
0417:                        }
0418:
0419:                    } while ((token == ',') || (token == JOIN));
0420:
0421:                    _parsingFrom = false;
0422:                }
0423:
0424:                int fromParseIndex = _parseIndex;
0425:                int fromToken = _token;
0426:
0427:                _parseIndex = oldParseIndex;
0428:                _token = oldToken;
0429:
0430:                ArrayList<AmberExpr> resultList = new ArrayList<AmberExpr>();
0431:
0432:                _parsingResult = true;
0433:
0434:                if (peekToken() == SELECT) {
0435:                    scanToken();
0436:
0437:                    if (peekToken() == DISTINCT) {
0438:                        scanToken();
0439:                        query.setDistinct(true);
0440:                    }
0441:
0442:                    String constructorName = null;
0443:
0444:                    if (peekToken() == NEW) {
0445:
0446:                        scanToken();
0447:
0448:                        // Scans the fully qualified constructor
0449:
0450:                        String s = "";
0451:
0452:                        boolean isDot = false;
0453:
0454:                        while ((token = scanToken()) != '(') {
0455:
0456:                            if (!isDot) {
0457:                                s += _lexeme;
0458:                                isDot = true;
0459:                            } else if (token == '.') {
0460:                                s += '.';
0461:                                isDot = false;
0462:                            } else
0463:                                throw error(L
0464:                                        .l(
0465:                                                "Constructor with SELECT NEW must be fully qualified. Expected '.' at {0}",
0466:                                                tokenName(token)));
0467:                        }
0468:
0469:                        constructorName = s;
0470:                    }
0471:
0472:                    do {
0473:
0474:                        AmberExpr expr = parseExpr();
0475:
0476:                        if (!hasFrom) {
0477:                            if (!(expr instanceof  DateTimeFunExpr))
0478:                                throw error(L
0479:                                        .l("expected FROM clause when the select clause has not date/time functions only"));
0480:                        } else {
0481:
0482:                            // jpa/1199
0483:                            if (expr == null)
0484:                                continue;
0485:
0486:                            expr = expr.bindSelect(this );
0487:
0488:                            if (_isLazyResult) {
0489:                            } else if (expr instanceof  PathExpr) {
0490:                                PathExpr pathExpr = (PathExpr) expr;
0491:
0492:                                FromItem rootItem = null;
0493:
0494:                                Type targetType = pathExpr.getTargetType();
0495:
0496:                                // jpa/0w24
0497:                                if (targetType instanceof  RelatedType) {
0498:                                    RelatedType relatedType = (RelatedType) targetType;
0499:                                    RelatedType parentType = relatedType;
0500:
0501:                                    while (parentType.getParentType() != null) {
0502:                                        if (parentType.getParentType() instanceof  EntityType)
0503:                                            parentType = parentType
0504:                                                    .getParentType();
0505:                                        else
0506:                                            break;
0507:                                    }
0508:
0509:                                    // jpa/0l4b
0510:                                    if (parentType != relatedType) {
0511:                                        FromItem child = pathExpr
0512:                                                .getChildFromItem();
0513:
0514:                                        Table table = relatedType.getTable(); // parentType.getTable();
0515:                                        ArrayList<LinkColumns> outgoingLinks = table
0516:                                                .getOutgoingLinks();
0517:
0518:                                        for (LinkColumns link : outgoingLinks) {
0519:                                            if (link.getTargetTable().equals(
0520:                                                    parentType.getTable())) {
0521:                                                rootItem = addFromItem(
0522:                                                        (EntityType) parentType,
0523:                                                        parentType.getTable());
0524:
0525:                                                JoinExpr join = new ManyToOneJoinExpr(
0526:                                                        link, rootItem, child);
0527:
0528:                                                rootItem.setJoinExpr(join);
0529:
0530:                                                rootItem
0531:                                                        .setJoinSemantics(FromItem.JoinSemantics.INNER);
0532:
0533:                                                break;
0534:                                            }
0535:                                        }
0536:                                    }
0537:                                }
0538:
0539:                                expr = LoadExpr.create(pathExpr, rootItem);
0540:
0541:                                expr = expr.bindSelect(this );
0542:                            }
0543:                        }
0544:
0545:                        resultList.add(expr);
0546:                    } while ((token = scanToken()) == ',');
0547:
0548:                    query.setHasFrom(hasFrom);
0549:
0550:                    if (hasFrom && (constructorName != null)) {
0551:
0552:                        if (token != ')')
0553:                            throw error(L
0554:                                    .l(
0555:                                            "Expected ')' at {0} when calling constructor with SELECT NEW",
0556:                                            tokenName(token)));
0557:
0558:                        token = scanToken();
0559:
0560:                        try {
0561:
0562:                            ClassLoader loader = Thread.currentThread()
0563:                                    .getContextClassLoader();
0564:
0565:                            Class cl = Class.forName(constructorName, false,
0566:                                    loader);
0567:
0568:                            query.setConstructorClass(cl);
0569:
0570:                        } catch (ClassNotFoundException ex) {
0571:                            throw error(L
0572:                                    .l(
0573:                                            "Unable to find class {0}. Make sure the class is fully qualified.",
0574:                                            constructorName));
0575:                        }
0576:                    }
0577:
0578:                    _token = token;
0579:                }
0580:
0581:                if (hasFrom && (peekToken() != FROM))
0582:                    throw error(L.l("expected FROM at {0}", tokenName(token)));
0583:
0584:                if (resultList.size() == 0) {
0585:
0586:                    if (_joinFetchMap.size() > 0)
0587:                        throw error(L
0588:                                .l("All associations referenced by JOIN FETCH must belong to an entity that is returned as a result of the query"));
0589:
0590:                    ArrayList<FromItem> fromList = _query.getFromList();
0591:
0592:                    if (fromList.size() > 0) {
0593:                        FromItem fromItem = fromList.get(0);
0594:
0595:                        AmberExpr expr = fromItem.getIdExpr();
0596:
0597:                        if (_isLazyResult) {
0598:                        } else if (expr instanceof  PathExpr) {
0599:                            PathExpr pathExpr = (PathExpr) expr;
0600:
0601:                            expr = LoadExpr.create(pathExpr);
0602:                            expr = expr.bindSelect(this );
0603:                        }
0604:
0605:                        resultList.add(expr);
0606:                    }
0607:                } else if (hasFrom) {
0608:
0609:                    int size = resultList.size();
0610:
0611:                    int matches = 0;
0612:
0613:                    for (int i = 0; i < size; i++) {
0614:
0615:                        AmberExpr expr = resultList.get(i);
0616:
0617:                        if (expr instanceof  LoadEntityExpr) {
0618:
0619:                            expr = ((LoadEntityExpr) expr).getExpr();
0620:
0621:                            if (_joinFetchMap.get(expr) != null) {
0622:                                matches++;
0623:                            }
0624:                        }
0625:                    }
0626:
0627:                    if (matches < _joinFetchMap.size())
0628:                        throw error(L
0629:                                .l("All associations referenced by JOIN FETCH must belong to an entity that is returned as a result of the query"));
0630:
0631:                }
0632:
0633:                // jpa/1199
0634:                if (_appendResultList != null)
0635:                    resultList.addAll(_appendResultList);
0636:
0637:                query.setResultList(resultList);
0638:
0639:                _parsingResult = false;
0640:
0641:                _parseIndex = fromParseIndex;
0642:                _token = fromToken;
0643:
0644:                token = peekToken();
0645:
0646:                boolean hasWhere = false;
0647:
0648:                if (token == WHERE) {
0649:                    scanToken();
0650:
0651:                    hasWhere = true;
0652:
0653:                    AmberExpr expr = parseExpr();
0654:
0655:                    // jpa/119l: WHERE SIZE() is moved to HAVING COUNT()
0656:                    if (expr != null) {
0657:                        expr = expr.createBoolean();
0658:
0659:                        query.setWhere(expr.bindSelect(this ));
0660:                    }
0661:                }
0662:
0663:                boolean hasGroupBy = false;
0664:
0665:                ArrayList<AmberExpr> groupList = _groupList;
0666:
0667:                token = peekToken();
0668:                if (token == GROUP) {
0669:                    scanToken();
0670:
0671:                    if (peekToken() == BY) {
0672:                        scanToken();
0673:                        hasGroupBy = true;
0674:                    }
0675:
0676:                    if (groupList == null)
0677:                        groupList = new ArrayList<AmberExpr>();
0678:
0679:                    while (true) {
0680:                        // jpa/0w23
0681:                        AmberExpr groupExpr = parseExpr();
0682:
0683:                        groupExpr = groupExpr.bindSelect(this );
0684:
0685:                        if (groupExpr instanceof  PathExpr) {
0686:                            // jpa/119n
0687:
0688:                            PathExpr pathExpr = (PathExpr) groupExpr;
0689:
0690:                            groupExpr = LoadExpr.create(pathExpr);
0691:
0692:                            groupExpr = groupExpr.bindSelect(this );
0693:                        }
0694:
0695:                        groupList.add(groupExpr);
0696:
0697:                        if (peekToken() == ',')
0698:                            scanToken();
0699:                        else
0700:                            break;
0701:                    }
0702:
0703:                    query.setGroupList(groupList);
0704:
0705:                    // Reset temp group list after parsing subselect.
0706:                    _groupList = null;
0707:                }
0708:
0709:                token = peekToken();
0710:                if (token == HAVING) {
0711:
0712:                    if (!hasGroupBy)
0713:                        throw error(L
0714:                                .l("Use of HAVING without GROUP BY is not currently supported"));
0715:
0716:                    _parsingHaving = true;
0717:
0718:                    scanToken();
0719:
0720:                    AmberExpr havingExpr = parseExpr();
0721:
0722:                    // jpa/119l: SIZE()
0723:                    if (_havingExpr != null)
0724:                        havingExpr = AndExpr.create(havingExpr, _havingExpr);
0725:
0726:                    query
0727:                            .setHaving(havingExpr.createBoolean().bindSelect(
0728:                                    this ));
0729:
0730:                    _parsingHaving = false;
0731:                } else if (hasWhere && _havingExpr != null) { // jpa/1199, jpa/119l
0732:                    query.setHaving(_havingExpr.createBoolean()
0733:                            .bindSelect(this ));
0734:                }
0735:
0736:                token = peekToken();
0737:                if (token == ORDER) {
0738:                    scanToken();
0739:
0740:                    if (peekToken() == BY)
0741:                        scanToken();
0742:
0743:                    ArrayList<AmberExpr> orderList = new ArrayList<AmberExpr>();
0744:                    ArrayList<Boolean> ascList = new ArrayList<Boolean>();
0745:
0746:                    while (true) {
0747:                        AmberExpr expr = parseExpr();
0748:
0749:                        // jpa/1114
0750:                        if (isCollectionExpr(expr))
0751:                            throw error(L.l(
0752:                                    "Unexpected collection at ORDER BY '{0}'.",
0753:                                    expr.getClass().getName()));
0754:
0755:                        expr = expr.bindSelect(this );
0756:
0757:                        orderList.add(expr);
0758:
0759:                        if (peekToken() == DESC) {
0760:                            scanToken();
0761:                            ascList.add(Boolean.FALSE);
0762:                        } else if (peekToken() == ASC) {
0763:                            scanToken();
0764:                            ascList.add(Boolean.TRUE);
0765:                        } else
0766:                            ascList.add(Boolean.TRUE);
0767:
0768:                        if (peekToken() == ',')
0769:                            scanToken();
0770:                        else
0771:                            break;
0772:                    }
0773:
0774:                    query.setOrderList(orderList, ascList);
0775:                }
0776:
0777:                token = peekToken();
0778:
0779:                if (token == OFFSET) {
0780:                    scanToken();
0781:
0782:                    token = scanToken();
0783:                    if (token != INTEGER)
0784:                        throw error(L.l("Expected INTEGER at {0}",
0785:                                tokenName(token)));
0786:
0787:                    int offset = Integer.parseInt(_lexeme);
0788:
0789:                    token = peekToken();
0790:
0791:                    query.setOffset(offset);
0792:                }
0793:
0794:                if (token == LIMIT) {
0795:                    scanToken();
0796:
0797:                    token = scanToken();
0798:                    if (token != INTEGER)
0799:                        throw error(L.l("Expected INTEGER at {0}",
0800:                                tokenName(token)));
0801:
0802:                    int limit = Integer.parseInt(_lexeme);
0803:                    query.setLimit(limit);
0804:
0805:                    token = peekToken();
0806:                }
0807:
0808:                if (!innerSelect) {
0809:                    query.setJoinFetchMap(_joinFetchMap);
0810:
0811:                    if (token > 0)
0812:                        throw error(L.l("expected end of query at {0}",
0813:                                tokenName(token)));
0814:
0815:                    if (!query.setArgList(_argList.toArray(new ArgExpr[_argList
0816:                            .size()])))
0817:                        throw error(L
0818:                                .l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters"));
0819:
0820:                }
0821:
0822:                query.init();
0823:
0824:                _joinSemantics = oldJoinSemantics;
0825:                _isJoinFetch = oldIsJoinFetch;
0826:                _query = oldQuery;
0827:                _depth = oldDepth;
0828:                _havingExpr = oldHavingExpr;
0829:                _appendResultList = oldAppendResultList;
0830:
0831:                return query;
0832:            }
0833:
0834:            private AbstractQuery parseUpdate() throws QueryParseException {
0835:                UpdateQuery query = new UpdateQuery(_sql, getMetaData());
0836:                _query = query;
0837:
0838:                FromItem fromItem = parseFrom();
0839:
0840:                int token = scanToken();
0841:                if (token != SET)
0842:                    throw error(L.l("expected 'SET' at {0}", tokenName(token)));
0843:
0844:                ArrayList<AmberExpr> fields = new ArrayList<AmberExpr>();
0845:                ArrayList<AmberExpr> values = new ArrayList<AmberExpr>();
0846:
0847:                parseSetValues(fromItem, fields, values);
0848:
0849:                query.setFieldList(fields);
0850:                query.setValueList(values);
0851:
0852:                token = scanToken();
0853:                if (token == WHERE) {
0854:                    AmberExpr expr = parseExpr();
0855:
0856:                    query.setWhere(expr.createBoolean().bindSelect(this ));
0857:
0858:                    token = scanToken();
0859:                }
0860:
0861:                if (token >= 0)
0862:                    throw error(L.l("'{0}' not expected at end of query.",
0863:                            tokenName(token)));
0864:
0865:                if (!query.setArgList(_argList.toArray(new ArgExpr[_argList
0866:                        .size()])))
0867:                    throw error(L
0868:                            .l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters"));
0869:
0870:                query.init();
0871:
0872:                return query;
0873:            }
0874:
0875:            private AbstractQuery parseDelete() throws QueryParseException {
0876:                DeleteQuery query = new DeleteQuery(_sql, getMetaData());
0877:                _query = query;
0878:
0879:                int token = peekToken();
0880:                if (token == FROM)
0881:                    scanToken();
0882:
0883:                FromItem fromItem = parseFrom();
0884:
0885:                token = scanToken();
0886:                if (token == WHERE) {
0887:                    query
0888:                            .setWhere(parseExpr().createBoolean().bindSelect(
0889:                                    this ));
0890:
0891:                    token = scanToken();
0892:                }
0893:
0894:                if (token >= 0)
0895:                    throw error(L.l("'{0}' not expected at end of query.",
0896:                            tokenName(token)));
0897:
0898:                if (!query.setArgList(_argList.toArray(new ArgExpr[_argList
0899:                        .size()])))
0900:                    throw error(L
0901:                            .l("Unable to parse all query parameters. Make sure named parameters are not mixed with positional parameters"));
0902:
0903:                query.init();
0904:
0905:                return query;
0906:            }
0907:
0908:            /**
0909:             * Parses the set values.
0910:             */
0911:            private void parseSetValues(FromItem fromItem,
0912:                    ArrayList<AmberExpr> fields, ArrayList<AmberExpr> values)
0913:                    throws QueryParseException {
0914:                EntityType entity = fromItem.getEntityType();
0915:
0916:                int token = -1;
0917:
0918:                do {
0919:
0920:                    token = scanToken();
0921:
0922:                    AmberExpr expr = null;
0923:
0924:                    String name = _lexeme.toString();
0925:
0926:                    IdExpr tableExpr = getIdentifier(name);
0927:
0928:                    if (tableExpr != null) {
0929:                        expr = parsePath(tableExpr);
0930:                    } else {
0931:
0932:                        tableExpr = fromItem.getIdExpr();
0933:
0934:                        AmberExpr next = tableExpr.createField(this , name);
0935:
0936:                        if (next instanceof  PathExpr)
0937:                            expr = addPath((PathExpr) next);
0938:                        else if (next != null)
0939:                            expr = next;
0940:                    }
0941:
0942:                    expr = expr.bindSelect(this );
0943:
0944:                    fields.add(expr);
0945:
0946:                    if ((token = peekToken()) != EQ)
0947:                        throw error(L
0948:                                .l("expected '=' at {0}", tokenName(token)));
0949:
0950:                    scanToken();
0951:
0952:                    // jpa/1222 expr = parseSimpleTerm();
0953:                    expr = parseConcatExpr();
0954:
0955:                    if (expr.hasRelationship())
0956:                        throw error(L
0957:                                .l(
0958:                                        "UPDATE cannot set values with relationships. Unexpected path expression at {0}",
0959:                                        expr));
0960:
0961:                    expr = expr.bindSelect(this );
0962:
0963:                    values.add(expr);
0964:
0965:                } while ((token = scanToken()) == ',');
0966:
0967:                _token = token;
0968:            }
0969:
0970:            /**
0971:             * Parses the FROM block.  parseFrom's effect is to populate the
0972:             * core identifiers.
0973:             *
0974:             * <pre>
0975:             * from-item ::= schema AS? IDENTIFIER
0976:             * </pre>
0977:             */
0978:            private FromItem parseFrom() throws QueryParseException {
0979:                SchemaExpr schema = parseSchema();
0980:
0981:                String id;
0982:
0983:                int token = peekToken();
0984:                if (token == AS) {
0985:                    scanToken();
0986:                    token = peekToken();
0987:                    id = parseIdentifier();
0988:                } else if (token == IDENTIFIER)
0989:                    id = parseIdentifier();
0990:                else {
0991:                    // jpa/116c
0992:                    if (schema instanceof  OneToManySchemaExpr)
0993:                        id = createTableName();
0994:                    else
0995:                        id = schema.getTailName();
0996:                }
0997:
0998:                /*
0999:                  AmberEntityHome home = _persistenceUnit.getHomeBySchema(schema);
1000:
1001:                  if (home == null)
1002:                  throw error(L.l("`{0}' is an unknown persistent class.",
1003:                  schema));
1004:                 */
1005:
1006:                FromItem item = schema.addFromItem(this , id);
1007:
1008:                if (schema instanceof  EmbeddedSchemaExpr) {
1009:
1010:                    // jpa/0w22
1011:
1012:                    EmbeddedSchemaExpr embeddedSchema = (EmbeddedSchemaExpr) schema;
1013:
1014:                    _query.addEmbeddedAlias(id, embeddedSchema.getExpr()); // pathString);
1015:                }
1016:
1017:                // jpa/114h
1018:                item.setJoinSemantics(_joinSemantics);
1019:
1020:                return item;
1021:            }
1022:
1023:            /**
1024:             * Adds a new FromItem.
1025:             */
1026:            public FromItem addFromItem(Table table) {
1027:                return addFromItem(null, table, createTableName());
1028:            }
1029:
1030:            /**
1031:             * Adds a new FromItem.
1032:             */
1033:            public FromItem addFromItem(EntityType entityType, Table table) {
1034:                return addFromItem(entityType, table, createTableName());
1035:            }
1036:
1037:            /**
1038:             * Returns a unique table name
1039:             */
1040:            public String createTableName() {
1041:                return "caucho" + _unique++;
1042:            }
1043:
1044:            /**
1045:             * Adds a new FromItem.
1046:             */
1047:            public FromItem addFromItem(Table table, String id) {
1048:                return addFromItem(null, table, id);
1049:            }
1050:
1051:            /**
1052:             * Adds a new FromItem.
1053:             */
1054:            public FromItem addFromItem(EntityType entityType, Table table,
1055:                    String id) {
1056:                if (id == null)
1057:                    id = createTableName();
1058:
1059:                FromItem item = _query.createFromItem(entityType, table, id);
1060:
1061:                item.setJoinSemantics(_joinSemantics);
1062:
1063:                return item;
1064:            }
1065:
1066:            /**
1067:             * Adds a new FromItem.
1068:             */
1069:            public FromItem createDependentFromItem(FromItem item,
1070:                    LinkColumns link) {
1071:                item = _query.createDependentFromItem(item, link,
1072:                        createTableName());
1073:
1074:                item.setJoinSemantics(_joinSemantics);
1075:
1076:                return item;
1077:            }
1078:
1079:            /**
1080:             * Adds a new link
1081:             */
1082:            void addLink(AmberExpr expr) {
1083:                // _andExpr.add(expr);
1084:                throw new IllegalStateException();
1085:            }
1086:
1087:            /**
1088:             * Adds an entity path
1089:             */
1090:            public PathExpr addPath(PathExpr path) {
1091:                PathExpr oldPath = _pathMap.get(path);
1092:
1093:                if (oldPath != null)
1094:                    return oldPath;
1095:
1096:                _pathMap.put(path, path);
1097:
1098:                return path;
1099:            }
1100:
1101:            /**
1102:             * Adds a new argument
1103:             */
1104:            public void addArg(ArgExpr arg) {
1105:                _argList.add(arg);
1106:            }
1107:
1108:            /**
1109:             * Parses a schema.
1110:             */
1111:            private SchemaExpr parseSchema() throws QueryParseException {
1112:                int token = peekToken();
1113:                boolean isIn = token == IN;
1114:
1115:                if (isIn) {
1116:
1117:                    scanToken();
1118:
1119:                    _joinSemantics = FromItem.JoinSemantics.INNER;
1120:
1121:                    if ((token = scanToken()) != '(')
1122:                        throw error(L.l("expected '(' at '{0}'",
1123:                                tokenName(token)));
1124:                }
1125:
1126:                String name = parseIdentifier();
1127:
1128:                SchemaExpr schema = null;
1129:
1130:                if (!isIn) {
1131:                    AmberEntityHome home = _persistenceUnit
1132:                            .getHomeBySchema(name);
1133:
1134:                    if (home != null) {
1135:                        EntityType type = home.getEntityType();
1136:
1137:                        schema = new TableIdExpr(home.getEntityType(), type
1138:                                .getTable().getName());
1139:                    }
1140:                }
1141:
1142:                IdExpr id = null;
1143:
1144:                if (schema == null) {
1145:                    id = getIdentifier(name);
1146:
1147:                    if (id != null)
1148:                        schema = new FromIdSchemaExpr(id);
1149:                }
1150:
1151:                if (!isIn && schema == null) {
1152:                    while (peekToken() == '.') {
1153:                        scanToken();
1154:                        String segment = parseIdentifier();
1155:
1156:                        name = name + '.' + segment;
1157:
1158:                        AmberEntityHome home = _persistenceUnit
1159:                                .getHomeBySchema(name);
1160:
1161:                        if (home != null) {
1162:                            schema = new TableIdExpr(home.getEntityType(), name);
1163:                            break;
1164:                        }
1165:                    }
1166:                }
1167:
1168:                if (schema == null) {
1169:                    throw error(L.l("'{0}' is an unknown entity.", name));
1170:                }
1171:
1172:                name = "";
1173:                boolean isFirst = true;
1174:
1175:                while (peekToken() == '.') {
1176:                    scanToken();
1177:                    String segment = parseIdentifier();
1178:
1179:                    if (isFirst) {
1180:                        name += segment;
1181:                        isFirst = false;
1182:                    } else
1183:                        name += "." + segment;
1184:
1185:                    schema = schema.createField(this , segment);
1186:                }
1187:
1188:                if (_isJoinFetch && (!name.equals(""))) {
1189:                    _joinFetchMap.put(id, name);
1190:                }
1191:
1192:                if (isIn) {
1193:                    if ((token = scanToken()) != ')')
1194:                        throw error(L.l("expected ')' at '{0}'",
1195:                                tokenName(token)));
1196:                }
1197:
1198:                return schema;
1199:            }
1200:
1201:            /**
1202:             * Parses an expression.
1203:             */
1204:            private AmberExpr parseExpr() throws QueryParseException {
1205:                if (peekToken() == SELECT) {
1206:                    SelectQuery select = parseSelect(true);
1207:
1208:                    return new SubSelectExpr(select);
1209:                }
1210:
1211:                AmberExpr expr = parseOrExpr();
1212:
1213:                return expr; // .bindSelect(this);
1214:            }
1215:
1216:            /**
1217:             * Parses an or expression.
1218:             */
1219:            private AmberExpr parseOrExpr() throws QueryParseException {
1220:                AmberExpr expr = parseAndExpr();
1221:                OrExpr orExpr = null;
1222:
1223:                while (peekToken() == OR) {
1224:                    scanToken();
1225:
1226:                    if (orExpr == null) {
1227:                        orExpr = new OrExpr();
1228:                        orExpr.add(expr);
1229:                    }
1230:
1231:                    AmberExpr andExpr = parseAndExpr();
1232:
1233:                    if (andExpr == null)
1234:                        continue;
1235:
1236:                    orExpr.add(andExpr);
1237:                }
1238:
1239:                return orExpr == null ? expr : orExpr;
1240:            }
1241:
1242:            /**
1243:             * Parses an and expression.
1244:             */
1245:            private AmberExpr parseAndExpr() throws QueryParseException {
1246:                AmberExpr expr = parseNotExpr();
1247:                AndExpr andExpr = null;
1248:
1249:                while (peekToken() == AND) {
1250:                    scanToken();
1251:
1252:                    if (andExpr == null) {
1253:                        andExpr = new AndExpr();
1254:                        andExpr.add(expr);
1255:                    }
1256:
1257:                    AmberExpr notExpr = parseNotExpr();
1258:
1259:                    if (notExpr == null)
1260:                        continue;
1261:
1262:                    andExpr.add(notExpr);
1263:                }
1264:
1265:                return andExpr == null ? expr : andExpr;
1266:            }
1267:
1268:            /**
1269:             * Parses a NOT expression.
1270:             *
1271:             */
1272:            private AmberExpr parseNotExpr() throws QueryParseException {
1273:                AmberExpr expr;
1274:
1275:                if (peekToken() == NOT) {
1276:                    scanToken();
1277:
1278:                    expr = new UnaryExpr(NOT, parseCmpExpr());
1279:                } else
1280:                    expr = parseCmpExpr();
1281:
1282:                // jpa/1199, jpa/119l
1283:
1284:                if (_parsingResult || _parsingHaving)
1285:                    return expr;
1286:
1287:                if (!_isSizeFunExpr)
1288:                    return expr;
1289:
1290:                if (_havingExpr == null) {
1291:                    _havingExpr = expr;
1292:                } else if (expr != null) { // jpa/1199
1293:                    _havingExpr = AndExpr.create(_havingExpr, expr);
1294:                }
1295:
1296:                return null;
1297:            }
1298:
1299:            /**
1300:             * Parses a comparison expression.
1301:             *
1302:             * <pre>
1303:             * cmp-expr ::= add-expr '=' add-expr is-term?
1304:             *          ::= add-expr 'NOT'? 'BETWEEN' add-expr 'AND' add-expr is-term?
1305:             *          ::= add-expr 'NOT'? 'LIKE' string ('ESCAPE' string)? is-term?
1306:             *          ::= add-expr 'NOT'? 'IN' ('lit-1', ..., 'lit-n')
1307:             *          ::= add-expr
1308:             * </pre>
1309:             *
1310:             * @return the parsed expression
1311:             */
1312:            private AmberExpr parseCmpExpr() throws QueryParseException {
1313:                AmberExpr expr = parseConcatExpr();
1314:
1315:                int token = peekToken();
1316:                boolean isNot = false;
1317:
1318:                if (token == NOT) {
1319:                    scanToken();
1320:                    isNot = true;
1321:                    token = peekToken();
1322:
1323:                    if (token != BETWEEN && token != LIKE && token != MEMBER
1324:                            && token != IN)
1325:                        throw error(L.l("'NOT' is not expected here."));
1326:                }
1327:
1328:                if (token >= EQ && token <= GE) {
1329:                    scanToken();
1330:
1331:                    AmberExpr concatExpr = parseConcatExpr();
1332:
1333:                    return parseIs(new BinaryExpr(token, expr, concatExpr));
1334:                } else if (token == BETWEEN) {
1335:                    scanToken();
1336:
1337:                    AmberExpr min = parseConcatExpr();
1338:
1339:                    if ((token = scanToken()) != AND)
1340:                        throw error(L.l("Expected 'AND' at {0}",
1341:                                tokenName(token)));
1342:
1343:                    AmberExpr max = parseConcatExpr();
1344:
1345:                    // jpa/106a
1346:                    if (!isCompatibleExpression(expr, min))
1347:                        throw error(L
1348:                                .l(
1349:                                        "Expected compatible expression at {0} BETWEEN {1}",
1350:                                        expr, min));
1351:
1352:                    if (!isCompatibleExpression(expr, max))
1353:                        throw error(L
1354:                                .l(
1355:                                        "Expected compatible expression at BETWEEN {0} AND {1}",
1356:                                        min, max));
1357:
1358:                    return new BetweenExpr(expr, min, max, isNot);
1359:                } else if (token == LIKE) {
1360:                    scanToken();
1361:
1362:                    AmberExpr pattern = parseConcatExpr();
1363:
1364:                    // jpa/1075
1365:                    if (pattern instanceof  LiteralExpr) {
1366:                        LiteralExpr literalExpr = (LiteralExpr) pattern;
1367:
1368:                        if (literalExpr.getJavaType() != String.class)
1369:                            throw error(L.l("Expected string at {0}", pattern));
1370:                    } else if (!(pattern instanceof  ArgExpr)) // jpa/1076
1371:                        throw error(L.l("Expected string at {0}", pattern));
1372:
1373:                    String escape = null;
1374:                    if (peekToken() == ESCAPE) {
1375:                        scanToken();
1376:
1377:                        if ((token = scanToken()) != STRING)
1378:                            throw error(L.l("Expected string at {0}",
1379:                                    tokenName(token)));
1380:
1381:                        escape = _lexeme.toString();
1382:                    }
1383:
1384:                    return parseIs(new LikeExpr(expr, pattern, escape, isNot));
1385:                } else if (token == IN) {
1386:                    scanToken();
1387:                    token = scanToken();
1388:
1389:                    if (token != '(')
1390:                        throw error(L.l("Expected '(' after IN at {0}",
1391:                                tokenName(token)));
1392:
1393:                    ArrayList<AmberExpr> args = new ArrayList<AmberExpr>();
1394:                    while ((token = peekToken()) > 0 && token != ')') {
1395:                        AmberExpr arg = parseExpr();
1396:
1397:                        args.add(arg);
1398:
1399:                        token = peekToken();
1400:                        if (token == ',') {
1401:                            scanToken();
1402:                            token = peekToken();
1403:                        }
1404:                    }
1405:
1406:                    if (peekToken() != ')')
1407:                        throw error(L.l("Expected ')' after IN at {0}",
1408:                                tokenName(token)));
1409:
1410:                    scanToken();
1411:
1412:                    if (expr instanceof  IdExpr) {
1413:                        IdExpr idExpr = (IdExpr) expr;
1414:
1415:                        // jpa/1174
1416:                        if (idExpr.getFromItem().isEntityType())
1417:                            throw error(L.l("Unexpected entity at '{0} IN'",
1418:                                    expr));
1419:                    }
1420:
1421:                    return new InExpr(expr, args, isNot);
1422:                } else if (token == MEMBER) {
1423:                    scanToken();
1424:
1425:                    token = peekToken();
1426:                    if (token == OF)
1427:                        token = scanToken();
1428:
1429:                    AmberExpr collection = parseExpr();
1430:
1431:                    // jpa/10c8
1432:                    if (expr instanceof  ArgExpr) {
1433:                        addArg((ArgExpr) expr);
1434:                    } else if (!(expr instanceof  PathExpr))
1435:                        throw error(L
1436:                                .l("MEMBER OF requires an entity-valued item."));
1437:
1438:                    if (!isCollectionExpr(collection))
1439:                        throw error(L
1440:                                .l(
1441:                                        "MEMBER OF requires an entity-valued collection at '{0}'.",
1442:                                        collection.getClass().getName()));
1443:
1444:                    return parseIs(MemberExpr.create(this , expr, collection,
1445:                            isNot));
1446:                } else
1447:                    return parseIs(expr);
1448:            }
1449:
1450:            private AmberExpr parseIs(AmberExpr expr)
1451:                    throws QueryParseException {
1452:                int token = peekToken();
1453:
1454:                if (token != IS)
1455:                    return expr;
1456:
1457:                scanToken();
1458:
1459:                boolean isNot = false;
1460:                token = scanToken();
1461:
1462:                if (token == NOT) {
1463:                    isNot = true;
1464:                    token = scanToken();
1465:                }
1466:
1467:                if (token == NULL) {
1468:                    if (expr instanceof  KeyColumnExpr)
1469:                        expr = ((KeyColumnExpr) expr).getParent();
1470:                    else if (expr instanceof  IdExpr) {
1471:                        IdExpr idExpr = (IdExpr) expr;
1472:
1473:                        // jpa/1093
1474:                        if (idExpr.getFromItem().isEntityType())
1475:                            throw error(L.l("Unexpected entity at '{0} IS'",
1476:                                    expr));
1477:                    }
1478:
1479:                    if (isNot)
1480:                        return new UnaryExpr(NOT_NULL, expr);
1481:                    else
1482:                        return new UnaryExpr(NULL, expr);
1483:                } else if (token == EMPTY) {
1484:                    if (!isCollectionExpr(expr))
1485:                        throw error(L
1486:                                .l(
1487:                                        "IS EMPTY requires an entity-valued collection at '{0}'.",
1488:                                        expr.getClass().getName()));
1489:
1490:                    expr = new EmptyExpr(expr);
1491:
1492:                    if (!isNot)
1493:                        expr = new UnaryExpr(NOT, expr);
1494:
1495:                    return expr;
1496:                } else
1497:                    throw error(L.l("expected NULL at '{0}'", tokenName(token)));
1498:            }
1499:
1500:            /**
1501:             * Parses a concat expression.
1502:             */
1503:            private AmberExpr parseConcatExpr() throws QueryParseException {
1504:                AmberExpr expr = parseAddExpr();
1505:
1506:                while (true) {
1507:                    int token = peekToken();
1508:
1509:                    switch (token) {
1510:                    case CONCAT_OP:
1511:                        scanToken();
1512:
1513:                        ArrayList<AmberExpr> args = new ArrayList<AmberExpr>();
1514:
1515:                        args.add(expr);
1516:                        args.add(parseAddExpr());
1517:
1518:                        expr = ConcatFunExpr.create(this , args);
1519:                        break;
1520:                    default:
1521:                        return expr;
1522:                    }
1523:                }
1524:            }
1525:
1526:            /**
1527:             * Parses an add expression.
1528:             */
1529:            private AmberExpr parseAddExpr() throws QueryParseException {
1530:                AmberExpr expr = parseMulExpr();
1531:
1532:                while (true) {
1533:                    int token = peekToken();
1534:
1535:                    switch (token) {
1536:                    case '+':
1537:                    case '-':
1538:                        scanToken();
1539:                        expr = new BinaryExpr(token, expr, parseMulExpr());
1540:                        break;
1541:                    default:
1542:                        return expr;
1543:                    }
1544:                }
1545:            }
1546:
1547:            /**
1548:             * Parses a mul expression.
1549:             */
1550:            private AmberExpr parseMulExpr() throws QueryParseException {
1551:                AmberExpr expr = parseTerm();
1552:
1553:                while (true) {
1554:                    int token = peekToken();
1555:
1556:                    switch (token) {
1557:                    case '*':
1558:                    case '/':
1559:                        scanToken();
1560:                        expr = new BinaryExpr(token, expr, parseTerm());
1561:                        break;
1562:                    default:
1563:                        return expr;
1564:                    }
1565:                }
1566:            }
1567:
1568:            /**
1569:             * Parses a term
1570:             *
1571:             * <pre>
1572:             * term ::= - term
1573:             *      ::= + term
1574:             *      ::= NOT term
1575:             * </pre>
1576:             */
1577:            private AmberExpr parseTerm() throws QueryParseException {
1578:                int token = peekToken();
1579:
1580:                switch (token) {
1581:                case '+':
1582:                case '-':
1583:                case NOT:
1584:                    scanToken();
1585:
1586:                    return new UnaryExpr(token, parseTerm());
1587:
1588:                default:
1589:                    return parseSimpleTerm();
1590:                }
1591:            }
1592:
1593:            /**
1594:             * Parses a simple term
1595:             *
1596:             * <pre>
1597:             * term ::= INTEGER | LONG | DOUBLE | STRING
1598:             *      ::= THIS
1599:             *      ::= IDENTIFIER
1600:             *      ::= IDENTIFIER '(' args ')'
1601:             *      ::= '(' expr ')'
1602:             * </pre>
1603:             */
1604:            private AmberExpr parseSimpleTerm() throws QueryParseException {
1605:                int token = scanToken();
1606:
1607:                switch (token) {
1608:                case IDENTIFIER:
1609:                case LOCATE:
1610:                case LENGTH:
1611:                case MAX:
1612:                case MIN:
1613:                case SUM:
1614:                case ABS:
1615:                case SQRT:
1616:                case MOD:
1617:                case SIZE:
1618:                case CONCAT:
1619:                case LOWER:
1620:                case UPPER:
1621:                case SUBSTRING:
1622:                case TRIM: {
1623:                    String name = _lexeme.toString();
1624:
1625:                    if (peekToken() != '(') {
1626:                        // Either IdExpr or EmbeddedExpr
1627:                        AbstractPathExpr tableExpr = getIdentifier(name);
1628:
1629:                        if (tableExpr == null) {
1630:                            // jpa/0w22
1631:                            tableExpr = getEmbeddedAlias(name);
1632:                        }
1633:
1634:                        if (tableExpr == null) {
1635:                            // jpa/11z6
1636:                            AmberExpr amberExpr = parseEnum(name);
1637:
1638:                            if (amberExpr != null)
1639:                                return amberExpr;
1640:                        }
1641:
1642:                        if (tableExpr != null) {
1643:                            AmberExpr amberExpr = parsePath(tableExpr);
1644:
1645:                            return amberExpr;
1646:                        }
1647:
1648:                        if (_query.getFromList().size() == 0)
1649:                            throw error(L
1650:                                    .l("Expected a FROM clause before '{0}'",
1651:                                            name));
1652:
1653:                        FromItem fromItem = _query.getFromList().get(0);
1654:
1655:                        tableExpr = fromItem.getIdExpr();
1656:
1657:                        AmberExpr next = tableExpr.createField(this , name);
1658:
1659:                        if (next instanceof  PathExpr)
1660:                            return addPath((PathExpr) next);
1661:                        else if (next != null)
1662:                            return next;
1663:
1664:                        throw error(L.l("'{0}' is an unknown table or column",
1665:                                name));
1666:                    } else {
1667:
1668:                        name = name.toLowerCase();
1669:
1670:                        // EXISTS | ALL | ANY | SOME
1671:                        if (name.equals("exists") || name.equals("all")
1672:                                || name.equals("any") || name.equals("some")) {
1673:
1674:                            scanToken();
1675:
1676:                            if (peekToken() != SELECT && peekToken() != FROM)
1677:                                throw error(L.l(name.toUpperCase()
1678:                                        + " requires '(SELECT'"));
1679:
1680:                            SelectQuery select = parseSelect(true);
1681:
1682:                            if (peekToken() != ')')
1683:                                throw error(L.l(name.toUpperCase()
1684:                                        + " requires ')'"));
1685:
1686:                            scanToken();
1687:
1688:                            ArrayList<FromItem> parentFromList;
1689:                            parentFromList = select.getParentQuery()
1690:                                    .getFromList();
1691:
1692:                            // jpa/1178
1693:                            select.getFromList().addAll(0, parentFromList);
1694:
1695:                            if (name.equals("exists"))
1696:                                return new ExistsExpr(select);
1697:                            else if (name.equals("all"))
1698:                                return new AllExpr(select);
1699:                            else
1700:                                // SOME is a synonymous with ANY
1701:                                return new AnyExpr(select);
1702:                        } else {
1703:                            return parseFunction(name, token);
1704:                        }
1705:                    }
1706:                }
1707:
1708:                case CURRENT_DATE:
1709:                case CURRENT_TIME:
1710:                case CURRENT_TIMESTAMP: {
1711:                    String name = _lexeme.toString();
1712:
1713:                    return parseFunction(name, token);
1714:                }
1715:
1716:                case FALSE:
1717:                    return new LiteralExpr(this , _lexeme, boolean.class);
1718:
1719:                case TRUE:
1720:                    return new LiteralExpr(this , _lexeme, boolean.class);
1721:
1722:                case NULL:
1723:                    return new NullExpr();
1724:
1725:                case INTEGER:
1726:                    return new LiteralExpr(this , _lexeme, int.class);
1727:
1728:                case LONG:
1729:                    return new LiteralExpr(this , _lexeme, long.class);
1730:
1731:                case DOUBLE:
1732:                    return new LiteralExpr(this , _lexeme, double.class);
1733:
1734:                case STRING:
1735:                    return new LiteralExpr(this , _lexeme, String.class);
1736:
1737:                case ARG: {
1738:                    ArgExpr arg = new ArgExpr(this , Integer.parseInt(_lexeme));
1739:                    /*
1740:                      if (_addArgToQuery)
1741:                      addArg(arg);
1742:                     */
1743:                    return arg;
1744:                }
1745:
1746:                case NAMED_ARG: {
1747:                    ArgExpr arg = new ArgExpr(this , _lexeme, _parameterCount);
1748:                    return arg;
1749:                }
1750:
1751:                    /*
1752:                      case THIS:
1753:                      {
1754:                      if (_thisExpr == null) {
1755:                      _thisExpr = new IdExpr(this, "caucho_this", _bean);
1756:                      addFromItem("caucho_this", _bean.getSQLTable());
1757:                      _argList.add(0, new ThisExpr(this, _bean));
1758:                      }
1759:
1760:                      return _thisExpr;
1761:                      }
1762:                     */
1763:
1764:                case '(':
1765:                    AmberExpr expr = parseExpr();
1766:                    if ((token = scanToken()) != ')')
1767:                        throw error(L
1768:                                .l("expected `)' at {0}", tokenName(token)));
1769:
1770:                    return expr;
1771:
1772:                default:
1773:                    throw error(L.l("expected term at {0}", tokenName(token)));
1774:                }
1775:            }
1776:
1777:            /**
1778:             * Parses a path
1779:             *
1780:             * <pre>
1781:             * path ::= IDENTIFIER
1782:             *      ::= path . IDENTIFIER
1783:             * </pre>
1784:             */
1785:            private AmberExpr parsePath(PathExpr path)
1786:                    throws QueryParseException {
1787:                while (peekToken() == '.') {
1788:                    scanToken();
1789:
1790:                    String field = parseIdentifier();
1791:
1792:                    AmberExpr next = path.createField(this , field);
1793:
1794:                    if (next == null)
1795:                        throw error(L.l("'{0}' does not have a field '{1}'",
1796:                                path, field));
1797:
1798:                    if (!(next instanceof  PathExpr))
1799:                        return next;
1800:
1801:                    PathExpr nextPath = addPath((PathExpr) next);
1802:
1803:                    if (peekToken() == '[') {
1804:                        scanToken();
1805:
1806:                        AmberExpr index = parseExpr();
1807:
1808:                        next = nextPath.createArray(index);
1809:
1810:                        if (next == null)
1811:                            throw error(L.l(
1812:                                    "'{0}' does not have a map field '{1}'",
1813:                                    path, field));
1814:
1815:                        if (peekToken() != ']') {
1816:                            throw error(L.l("expected ']' at '{0}'",
1817:                                    tokenName(peekToken())));
1818:                        }
1819:
1820:                        scanToken();
1821:                    }
1822:
1823:                    if (next instanceof  PathExpr)
1824:                        path = addPath((PathExpr) next);
1825:                    else
1826:                        return next;
1827:                }
1828:
1829:                return path;
1830:            }
1831:
1832:            /**
1833:             * Parses a enum value
1834:             *
1835:             * <pre>
1836:             * enum ::= (IDENTIFIER '.')+ IDENTIFIER
1837:             * </pre>
1838:             */
1839:            private EnumExpr parseEnum(String head) throws QueryParseException {
1840:                CharBuffer cb = CharBuffer.allocate();
1841:
1842:                int token;
1843:
1844:                while ((token = scanToken()) == '.') {
1845:
1846:                    if (cb.length() > 0)
1847:                        cb.append('.');
1848:
1849:                    cb.append(head);
1850:
1851:                    token = scanToken();
1852:
1853:                    if (token != IDENTIFIER)
1854:                        throw error(L
1855:                                .l(
1856:                                        "expected identifier for enumerated type {0} at {1}",
1857:                                        cb.toString(), tokenName(token)));
1858:
1859:                    head = _lexeme.toString();
1860:                }
1861:
1862:                int value = -1;
1863:                Class cl = null;
1864:
1865:                try {
1866:                    ClassLoader loader = Thread.currentThread()
1867:                            .getContextClassLoader();
1868:
1869:                    cl = Class.forName(cb.toString(), false, loader);
1870:
1871:                    Enum enumValue = Enum.valueOf(cl, head);
1872:
1873:                    value = enumValue.ordinal();
1874:                } catch (ClassNotFoundException e) {
1875:                    // Not an error; only this is not a enum.
1876:                    // Continue - see parseSimpleTerm().
1877:                    return null;
1878:                }
1879:
1880:                return new EnumExpr(cl, head, value);
1881:            }
1882:
1883:            /**
1884:             * Parses a function
1885:             *
1886:             * <pre>
1887:             * fun ::= IDENTIFIER ( expr* )
1888:             *     ::= IDENTIFIER ( DISTINCT expr* )
1889:             * </pre>
1890:             */
1891:            private AmberExpr parseFunction(String id, int functionToken)
1892:                    throws QueryParseException {
1893:                // Function with no arguments.
1894:                switch (functionToken) {
1895:
1896:                case CURRENT_DATE:
1897:                    return CurrentDateFunExpr.create(this );
1898:
1899:                case CURRENT_TIME:
1900:                    return CurrentTimeFunExpr.create(this );
1901:
1902:                case CURRENT_TIMESTAMP:
1903:                    return CurrentTimestampFunExpr.create(this );
1904:                }
1905:
1906:                // Function with arguments.
1907:
1908:                scanToken();
1909:
1910:                // Example: "'c'"
1911:                AmberExpr trimChar = null;
1912:                TrimFunExpr.TrimSemantics trimSemantics = TrimFunExpr.TrimSemantics.BOTH;
1913:                boolean distinct = false;
1914:
1915:                ArrayList<AmberExpr> args = new ArrayList<AmberExpr>();
1916:
1917:                if (functionToken == TRIM) {
1918:
1919:                    switch (peekToken()) {
1920:
1921:                    case LEADING:
1922:                        trimSemantics = TrimFunExpr.TrimSemantics.LEADING;
1923:                        scanToken();
1924:                        break;
1925:
1926:                    case TRAILING:
1927:                        trimSemantics = TrimFunExpr.TrimSemantics.TRAILING;
1928:                        scanToken();
1929:                        break;
1930:
1931:                    case BOTH:
1932:                        scanToken();
1933:                        break;
1934:
1935:                    // default: [BOTH], but no scanToken().
1936:                    }
1937:
1938:                    AmberExpr arg = null;
1939:
1940:                    if (peekToken() != FROM) {
1941:
1942:                        arg = parseExpr();
1943:
1944:                        if (arg instanceof  LiteralExpr) {
1945:
1946:                            String v = ((LiteralExpr) arg).getValue();
1947:
1948:                            if (v.length() != 3) // "'c'"
1949:                                throw error(L
1950:                                        .l(
1951:                                                "expected a single char expression for TRIM at {0}",
1952:                                                v));
1953:                        }
1954:                    }
1955:
1956:                    if (peekToken() == FROM) {
1957:                        scanToken();
1958:
1959:                        trimChar = arg;
1960:
1961:                        arg = parseExpr();
1962:                    }
1963:
1964:                    args.add(arg);
1965:                } else {
1966:
1967:                    if (peekToken() == DISTINCT) {
1968:                        distinct = true;
1969:                        scanToken();
1970:                    }
1971:
1972:                    while ((peekToken() >= 0) && (peekToken() != ')')) {
1973:
1974:                        AmberExpr arg = parseExpr();
1975:
1976:                        if (id.equalsIgnoreCase("object")) {
1977:                            if (arg instanceof  PathExpr) {
1978:                                PathExpr pathExpr = (PathExpr) arg;
1979:
1980:                                arg = LoadExpr.create(pathExpr);
1981:
1982:                                arg = arg.bindSelect(this );
1983:
1984:                                int token = scanToken();
1985:
1986:                                if (token != ')')
1987:                                    throw error(L.l("expected ')' at '{0}'",
1988:                                            tokenName(token)));
1989:
1990:                                return arg;
1991:                            }
1992:                        }
1993:
1994:                        args.add(arg);
1995:
1996:                        if (peekToken() != ',')
1997:                            break;
1998:
1999:                        scanToken();
2000:                    }
2001:                }
2002:
2003:                if (peekToken() != ')')
2004:                    throw error(L.l("expected ')' at '{0}'",
2005:                            tokenName(scanToken())));
2006:
2007:                scanToken();
2008:
2009:                FunExpr funExpr;
2010:
2011:                switch (functionToken) {
2012:
2013:                case LOCATE:
2014:                    funExpr = LocateFunExpr.create(this , args);
2015:                    break;
2016:
2017:                case LENGTH:
2018:                    funExpr = LengthFunExpr.create(this , args);
2019:                    break;
2020:
2021:                case MAX:
2022:                    funExpr = MaxFunExpr.create(this , id, args, distinct);
2023:                    break;
2024:
2025:                case MIN:
2026:                    funExpr = MinFunExpr.create(this , id, args, distinct);
2027:                    break;
2028:
2029:                case SUM:
2030:                    funExpr = SumFunExpr.create(this , id, args, distinct);
2031:                    break;
2032:
2033:                case ABS:
2034:                    funExpr = AbsFunExpr.create(this , args);
2035:                    break;
2036:
2037:                case SQRT:
2038:                    funExpr = SqrtFunExpr.create(this , args);
2039:                    break;
2040:
2041:                case MOD:
2042:                    funExpr = ModFunExpr.create(this , args);
2043:                    break;
2044:
2045:                case SIZE:
2046:                    if (!(_query instanceof  SelectQuery))
2047:                        throw error(L
2048:                                .l("The SIZE() function is only supported for SELECT or subselect queries"));
2049:
2050:                    // jpa/119l
2051:
2052:                    AmberExpr arg = args.get(0);
2053:                    if (arg instanceof  ManyToOneExpr) {
2054:                        // @ManyToMany
2055:                        arg = ((ManyToOneExpr) arg).getParent();
2056:                    }
2057:
2058:                    if (!(arg instanceof  OneToManyExpr))
2059:                        throw error(L
2060:                                .l(
2061:                                        "The SIZE() function is only supported for @ManyToMany or @OneToMany relationships. The argument '{0}' is not supported.",
2062:                                        args.get(0)));
2063:
2064:                    OneToManyExpr oneToMany = (OneToManyExpr) arg;
2065:
2066:                    _groupList = new ArrayList<AmberExpr>();
2067:
2068:                    LinkColumns linkColumns = oneToMany.getLinkColumns();
2069:                    ForeignColumn fkColumn = linkColumns.getColumns().get(0);
2070:
2071:                    AmberExpr groupExpr = oneToMany.getParent();
2072:
2073:                    if (groupExpr instanceof  PathExpr) {
2074:                        // jpa/119n
2075:
2076:                        PathExpr pathExpr = (PathExpr) groupExpr;
2077:
2078:                        groupExpr = LoadExpr.create(pathExpr);
2079:
2080:                        groupExpr = groupExpr.bindSelect(this );
2081:                    }
2082:
2083:                    // groupExpr = new ColumnExpr(oneToMany.getParent(),
2084:                    //                            fkColumn.getTargetColumn());
2085:
2086:                    _groupList.add(groupExpr);
2087:
2088:                    ((SelectQuery) _query).setGroupList(_groupList);
2089:
2090:                    funExpr = SizeFunExpr.create(this , args);
2091:
2092:                    // jpa/1199, jpa/119l
2093:                    if (!_parsingResult) {
2094:                        if (_query instanceof  SelectQuery) {
2095:                            SelectQuery query = (SelectQuery) _query;
2096:                            ArrayList<AmberExpr> resultList = query
2097:                                    .getResultList();
2098:
2099:                            for (AmberExpr expr : resultList) {
2100:                                if (expr instanceof  SizeFunExpr) {
2101:                                    SizeFunExpr sizeFun = (SizeFunExpr) expr;
2102:                                    AmberExpr amberExpr = sizeFun.getArgs()
2103:                                            .get(0);
2104:
2105:                                    // @ManyToMany
2106:                                    if (amberExpr instanceof  ManyToOneExpr) {
2107:                                        amberExpr = ((ManyToOneExpr) amberExpr)
2108:                                                .getParent();
2109:                                    }
2110:
2111:                                    if (amberExpr.equals(arg))
2112:                                        args.set(0, amberExpr);
2113:                                }
2114:                            }
2115:                        }
2116:
2117:                        if (_appendResultList == null)
2118:                            _appendResultList = new ArrayList<AmberExpr>();
2119:
2120:                        _appendResultList.add(funExpr.bindSelect(this ));
2121:
2122:                        _isSizeFunExpr = true;
2123:                    }
2124:
2125:                    break;
2126:
2127:                case CONCAT:
2128:                    funExpr = ConcatFunExpr.create(this , args);
2129:                    break;
2130:
2131:                case LOWER:
2132:                    funExpr = LowerFunExpr.create(this , args);
2133:                    break;
2134:
2135:                case UPPER:
2136:                    funExpr = UpperFunExpr.create(this , args);
2137:                    break;
2138:
2139:                case SUBSTRING:
2140:                    funExpr = SubstringFunExpr.create(this , args);
2141:                    break;
2142:
2143:                case TRIM: {
2144:                    TrimFunExpr trimFunExpr = TrimFunExpr.create(this , args);
2145:                    trimFunExpr.setTrimChar(trimChar);
2146:                    trimFunExpr.setTrimSemantics(trimSemantics);
2147:                    funExpr = trimFunExpr;
2148:                    break;
2149:                }
2150:
2151:                default:
2152:                    funExpr = FunExpr.create(this , id, args, distinct);
2153:                }
2154:
2155:                return funExpr;
2156:            }
2157:
2158:            /**
2159:             * Returns the matching identifier.
2160:             */
2161:            private IdExpr getIdentifier(String name)
2162:                    throws QueryParseException {
2163:                AbstractQuery query = _query;
2164:
2165:                for (; query != null; query = query.getParentQuery()) {
2166:                    ArrayList<FromItem> fromList = query.getFromList();
2167:
2168:                    for (int i = 0; i < fromList.size(); i++) {
2169:                        FromItem from = fromList.get(i);
2170:
2171:                        if (from.getName().equalsIgnoreCase(name))
2172:                            return from.getIdExpr();
2173:                    }
2174:                }
2175:
2176:                return null;
2177:
2178:                // throw error(L.l("`{0}' is an unknown table", name));
2179:            }
2180:
2181:            /**
2182:             * Returns the matching embedded alias.
2183:             */
2184:            private EmbeddedExpr getEmbeddedAlias(String name)
2185:                    throws QueryParseException {
2186:                // jpa/0w22
2187:
2188:                AbstractQuery query = _query;
2189:
2190:                for (; query != null; query = query.getParentQuery()) {
2191:                    HashMap<String, EmbeddedExpr> embeddedAliases = query
2192:                            .getEmbeddedAliases();
2193:
2194:                    for (Map.Entry<String, EmbeddedExpr> entry : embeddedAliases
2195:                            .entrySet()) {
2196:
2197:                        if (entry.getKey().equalsIgnoreCase(name))
2198:                            return entry.getValue();
2199:                    }
2200:                }
2201:
2202:                return null;
2203:            }
2204:
2205:            /**
2206:             * Returns true if expr is a collection.
2207:             */
2208:            private boolean isCollectionExpr(AmberExpr expr) {
2209:                // jpa/10a2
2210:
2211:                // ManyToMany is implemented as a
2212:                // ManyToOne[embeddeding OneToMany]
2213:                if ((expr instanceof  ManyToOneExpr)
2214:                        && (((ManyToOneExpr) expr).getParent() instanceof  OneToManyExpr))
2215:                    return true;
2216:                else if (expr instanceof  OneToManyExpr)
2217:                    return true;
2218:                else if (expr instanceof  CollectionIdExpr)
2219:                    return true;
2220:
2221:                return false;
2222:            }
2223:
2224:            /**
2225:             * Returns true if expr1 and expr2 are compatible.
2226:             */
2227:            private boolean isCompatibleExpression(AmberExpr expr1,
2228:                    AmberExpr expr2) {
2229:                // XXX: jpa/106a
2230:                if (expr1 instanceof  LiteralExpr) {
2231:                    if (expr2 instanceof  LiteralExpr) {
2232:                        Class javaType1 = ((LiteralExpr) expr1).getJavaType();
2233:                        Class javaType2 = ((LiteralExpr) expr2).getJavaType();
2234:
2235:                        if (javaType1.isAssignableFrom(javaType2))
2236:                            return true;
2237:
2238:                        return false;
2239:                    }
2240:                }
2241:
2242:                return true;
2243:            }
2244:
2245:            /**
2246:             * Parses an identifier.
2247:             */
2248:            private String parseIdentifier() throws QueryParseException {
2249:                int token = scanToken();
2250:
2251:                String identifier = _lexeme;
2252:
2253:                // Resolves ambiguous identifiers:
2254:                // 1. 'order': "SELECT o FROM Order o"
2255:                if (token == ORDER) {
2256:                    int parseIndex = _parseIndex;
2257:
2258:                    scanToken();
2259:
2260:                    if (peekToken() != BY) {
2261:                        token = IDENTIFIER;
2262:
2263:                        // Restores parse index right after ORDER BY.
2264:                        _parseIndex = parseIndex;
2265:                        _lexeme = identifier;
2266:                        _token = -1;
2267:                    }
2268:                } // 2. 'member': "SELECT m FROM Member m" (jpa/0x02)
2269:                else if (_parsingFrom && token == MEMBER) {
2270:                    token = IDENTIFIER;
2271:                }
2272:
2273:                if (token != IDENTIFIER) {
2274:                    throw error(L.l("expected identifier at `{0}'",
2275:                            tokenName(token)));
2276:                }
2277:
2278:                return identifier;
2279:            }
2280:
2281:            /**
2282:             * Peeks the next token
2283:             *
2284:             * @return integer code for the token
2285:             */
2286:            private int peekToken() throws QueryParseException {
2287:                if (_token > 0)
2288:                    return _token;
2289:
2290:                _token = scanToken();
2291:
2292:                return _token;
2293:            }
2294:
2295:            /**
2296:             * Scan the next token.  If the lexeme is a string, its string
2297:             * representation is in "lexeme".
2298:             *
2299:             * @return integer code for the token
2300:             */
2301:            private int scanToken() throws QueryParseException {
2302:                if (_token > 0) {
2303:                    int value = _token;
2304:                    _token = -1;
2305:                    return value;
2306:                }
2307:
2308:                int sign = 1;
2309:                int ch;
2310:
2311:                for (ch = read(); Character.isWhitespace((char) ch); ch = read()) {
2312:                }
2313:
2314:                switch (ch) {
2315:                case -1:
2316:                case '.':
2317:                case '*':
2318:                case '/':
2319:                case ',':
2320:                case '+':
2321:                case '-':
2322:                case '[':
2323:                case ']':
2324:                    return ch;
2325:
2326:                case '(':
2327:                    _depth++;
2328:                    return ch;
2329:
2330:                case ')':
2331:                    _depth--;
2332:                    return ch;
2333:
2334:                case '=':
2335:                    if ((ch = read()) == '>')
2336:                        return EXTERNAL_DOT;
2337:                    else {
2338:                        unread(ch);
2339:                        return EQ;
2340:                    }
2341:
2342:                case '!':
2343:                    if ((ch = read()) == '=')
2344:                        return NE;
2345:                    else {
2346:                        unread(ch);
2347:                        return '!';
2348:                    }
2349:
2350:                case '<':
2351:                    if ((ch = read()) == '=')
2352:                        return LE;
2353:                    else if (ch == '>')
2354:                        return NE;
2355:                    else {
2356:                        unread(ch);
2357:                        return LT;
2358:                    }
2359:
2360:                case '>':
2361:                    if ((ch = read()) == '=')
2362:                        return GE;
2363:                    else {
2364:                        unread(ch);
2365:                        return GT;
2366:                    }
2367:
2368:                case '?':
2369:                    CharBuffer cb = CharBuffer.allocate();
2370:                    int index = 0;
2371:                    for (ch = read(); ch >= '0' && ch <= '9'; ch = read()) {
2372:                        cb.append((char) ch);
2373:                        index = 10 * index + ch - '0';
2374:                    }
2375:                    unread(ch);
2376:
2377:                    _lexeme = cb.close();
2378:
2379:                    if (_lexeme.length() == 0) {
2380:                        _lexeme = String.valueOf(++_parameterCount);
2381:                    } else if (index <= 0)
2382:                        throw error(L.l(
2383:                                "`{0}' must refer to a positive argument", "?"
2384:                                        + _lexeme));
2385:
2386:                    return ARG;
2387:
2388:                case ':':
2389:                    if (Character.isJavaIdentifierStart((char) (ch = read()))) {
2390:                        cb = CharBuffer.allocate();
2391:
2392:                        for (; ch > 0
2393:                                && Character.isJavaIdentifierPart((char) ch); ch = read())
2394:                            cb.append((char) ch);
2395:
2396:                        unread(ch);
2397:
2398:                        _lexeme = cb.close();
2399:
2400:                        _parameterCount++;
2401:                    } else
2402:                        throw error(L.l(
2403:                                "`{0}' must be a valid parameter identifier",
2404:                                ":" + ((char) ch)));
2405:
2406:                    return NAMED_ARG;
2407:
2408:                case '|':
2409:                    if ((ch = read()) == '|')
2410:                        return CONCAT_OP;
2411:                    else
2412:                        throw error(L.l("unexpected char at {0}", String
2413:                                .valueOf((char) ch)));
2414:
2415:                    // @@ is useless?
2416:                case '@':
2417:                    if ((ch = read()) != '@')
2418:                        throw error(L.l("`@' expected at {0}", charName(ch)));
2419:                    return scanToken();
2420:                }
2421:
2422:                if (Character.isJavaIdentifierStart((char) ch)) {
2423:                    CharBuffer cb = CharBuffer.allocate();
2424:
2425:                    for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read())
2426:                        cb.append((char) ch);
2427:
2428:                    unread(ch);
2429:
2430:                    _lexeme = cb.close();
2431:                    String lower = _lexeme.toLowerCase();
2432:
2433:                    int token = _reserved.get(lower);
2434:
2435:                    if (token > 0)
2436:                        return token;
2437:                    else
2438:                        return IDENTIFIER;
2439:                } else if (ch >= '0' && ch <= '9') {
2440:                    CharBuffer cb = CharBuffer.allocate();
2441:
2442:                    int type = INTEGER;
2443:
2444:                    if (sign < 0)
2445:                        cb.append('-');
2446:
2447:                    for (; ch >= '0' && ch <= '9'; ch = read())
2448:                        cb.append((char) ch);
2449:
2450:                    if (ch == '.') {
2451:                        type = DOUBLE;
2452:
2453:                        cb.append('.');
2454:                        for (ch = read(); ch >= '0' && ch <= '9'; ch = read())
2455:                            cb.append((char) ch);
2456:                    }
2457:
2458:                    if (ch == 'e' || ch == 'E') {
2459:                        type = DOUBLE;
2460:
2461:                        cb.append('e');
2462:                        if ((ch = read()) == '+' || ch == '-') {
2463:                            cb.append((char) ch);
2464:                            ch = read();
2465:                        }
2466:
2467:                        if (!(ch >= '0' && ch <= '9'))
2468:                            throw error(L.l("exponent needs digits at {0}",
2469:                                    charName(ch)));
2470:
2471:                        for (; ch >= '0' && ch <= '9'; ch = read())
2472:                            cb.append((char) ch);
2473:                    }
2474:
2475:                    if (ch == 'F' || ch == 'D')
2476:                        type = DOUBLE;
2477:                    else if (ch == 'L') {
2478:                        type = LONG;
2479:                    } else
2480:                        unread(ch);
2481:
2482:                    _lexeme = cb.close();
2483:
2484:                    return type;
2485:                } else if (ch == '\'') {
2486:                    CharBuffer cb = CharBuffer.allocate();
2487:
2488:                    cb.append("'");
2489:                    for (ch = read(); ch >= 0; ch = read()) {
2490:                        if (ch == '\'') {
2491:                            if ((ch = read()) == '\'')
2492:                                cb.append("''");
2493:                            else {
2494:                                unread(ch);
2495:                                break;
2496:                            }
2497:                        } else
2498:                            cb.append((char) ch);
2499:                    }
2500:                    cb.append("'");
2501:
2502:                    _lexeme = cb.close();
2503:
2504:                    return STRING;
2505:                }
2506:
2507:                throw error(L.l("unexpected char at {0}", "" + (char) ch));
2508:            }
2509:
2510:            /**
2511:             * Returns the next character.
2512:             */
2513:            private int read() {
2514:                if (_parseIndex < _sql.length())
2515:                    return _sql.charAt(_parseIndex++);
2516:                else
2517:                    return -1;
2518:            }
2519:
2520:            /**
2521:             * Unread the last character.
2522:             */
2523:            private void unread(int ch) {
2524:                if (ch >= 0)
2525:                    _parseIndex--;
2526:            }
2527:
2528:            /**
2529:             * Returns the jdbc meta data, if available.
2530:             */
2531:            private JdbcMetaData getMetaData() {
2532:                if (_persistenceUnit == null)
2533:                    return null;
2534:
2535:                return _persistenceUnit.getMetaData();
2536:            }
2537:
2538:            /**
2539:             * Creates an error.
2540:             */
2541:            public QueryParseException error(String msg) {
2542:                msg += "\nin \"" + _sql + "\"";
2543:
2544:                return new QueryParseException(msg);
2545:            }
2546:
2547:            /**
2548:             * Returns the name for a character
2549:             */
2550:            private String charName(int ch) {
2551:                if (ch < 0)
2552:                    return L.l("end of query");
2553:                else
2554:                    return String.valueOf((char) ch);
2555:            }
2556:
2557:            /**
2558:             * Returns the name of a token
2559:             */
2560:            private String tokenName(int token) {
2561:                switch (token) {
2562:                case AS:
2563:                    return "AS";
2564:                case FROM:
2565:                    return "FROM";
2566:                case IN:
2567:                    return "IN";
2568:                case SELECT:
2569:                    return "SELECT";
2570:                case WHERE:
2571:                    return "WHERE";
2572:                case OR:
2573:                    return "OR";
2574:                case AND:
2575:                    return "AND";
2576:                case NOT:
2577:                    return "NOT";
2578:                case BETWEEN:
2579:                    return "BETWEEN";
2580:                case THIS:
2581:                    return "THIS";
2582:                case TRUE:
2583:                    return "FALSE";
2584:                case EMPTY:
2585:                    return "EMPTY";
2586:                case MEMBER:
2587:                    return "MEMBER";
2588:                case OF:
2589:                    return "OF";
2590:                case NULL:
2591:                    return "NULL";
2592:                case ORDER:
2593:                    return "ORDER";
2594:                case BY:
2595:                    return "BY";
2596:                case ASC:
2597:                    return "ASC";
2598:                case DESC:
2599:                    return "DESC";
2600:                case LIMIT:
2601:                    return "LIMIT";
2602:
2603:                case EXTERNAL_DOT:
2604:                    return "=>";
2605:
2606:                case -1:
2607:                    return L.l("end of query");
2608:
2609:                default:
2610:                    if (token < 128)
2611:                        return "'" + String.valueOf((char) token) + "'";
2612:                    else
2613:                        return "'" + _lexeme + "'";
2614:                }
2615:            }
2616:
2617:            /**
2618:             * Returns a debuggable description of the select.
2619:             */
2620:            public String toString() {
2621:                return "QueryParser[]";
2622:            }
2623:
2624:            static {
2625:                _reserved = new IntMap();
2626:                _reserved.put("as", AS);
2627:                _reserved.put("from", FROM);
2628:                _reserved.put("in", IN);
2629:                _reserved.put("select", SELECT);
2630:                _reserved.put("update", UPDATE);
2631:                _reserved.put("delete", DELETE);
2632:                _reserved.put("set", SET);
2633:                _reserved.put("distinct", DISTINCT);
2634:                _reserved.put("where", WHERE);
2635:                _reserved.put("order", ORDER);
2636:                _reserved.put("group", GROUP);
2637:                _reserved.put("by", BY);
2638:                _reserved.put("having", HAVING);
2639:                _reserved.put("asc", ASC);
2640:                _reserved.put("desc", DESC);
2641:                _reserved.put("limit", LIMIT);
2642:                _reserved.put("offset", OFFSET);
2643:
2644:                _reserved.put("join", JOIN);
2645:                _reserved.put("inner", INNER);
2646:                _reserved.put("left", LEFT);
2647:                _reserved.put("outer", OUTER);
2648:                _reserved.put("fetch", FETCH);
2649:
2650:                _reserved.put("or", OR);
2651:                _reserved.put("and", AND);
2652:                _reserved.put("not", NOT);
2653:
2654:                _reserved.put("length", LENGTH);
2655:                _reserved.put("locate", LOCATE);
2656:
2657:                _reserved.put("abs", ABS);
2658:                _reserved.put("sqrt", SQRT);
2659:                _reserved.put("mod", MOD);
2660:                _reserved.put("size", SIZE);
2661:
2662:                _reserved.put("max", MAX);
2663:                _reserved.put("min", MIN);
2664:                _reserved.put("sum", SUM);
2665:
2666:                _reserved.put("concat", CONCAT);
2667:                _reserved.put("lower", LOWER);
2668:                _reserved.put("upper", UPPER);
2669:                _reserved.put("substring", SUBSTRING);
2670:                _reserved.put("trim", TRIM);
2671:                _reserved.put("both", BOTH);
2672:                _reserved.put("leading", LEADING);
2673:                _reserved.put("trailing", TRAILING);
2674:
2675:                _reserved.put("current_date", CURRENT_DATE);
2676:                _reserved.put("current_time", CURRENT_TIME);
2677:                _reserved.put("current_timestamp", CURRENT_TIMESTAMP);
2678:
2679:                _reserved.put("between", BETWEEN);
2680:                _reserved.put("like", LIKE);
2681:                _reserved.put("escape", ESCAPE);
2682:                _reserved.put("is", IS);
2683:
2684:                _reserved.put("new", NEW);
2685:
2686:                _reserved.put("this", THIS);
2687:                _reserved.put("true", TRUE);
2688:                _reserved.put("false", FALSE);
2689:                _reserved.put("unknown", UNKNOWN);
2690:                _reserved.put("empty", EMPTY);
2691:                _reserved.put("member", MEMBER);
2692:                _reserved.put("of", OF);
2693:                _reserved.put("null", NULL);
2694:            }
2695:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.