Source Code Cross Referenced for Parser.java in  » Database-DBMS » hsql » org » hsqldb » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
0002:         * All rights reserved.
0003:         *
0004:         * Redistribution and use in source and binary forms, with or without
0005:         * modification, are permitted provided that the following conditions are met:
0006:         *
0007:         * Redistributions of source code must retain the above copyright notice, this
0008:         * list of conditions and the following disclaimer.
0009:         *
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:         * this list of conditions and the following disclaimer in the documentation
0012:         * and/or other materials provided with the distribution.
0013:         *
0014:         * Neither the name of the Hypersonic SQL Group nor the names of its
0015:         * contributors may be used to endorse or promote products derived from this
0016:         * software without specific prior written permission.
0017:         *
0018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021:         * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
0022:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029:         *
0030:         * This software consists of voluntary contributions made by many individuals 
0031:         * on behalf of the Hypersonic SQL Group.
0032:         *
0033:         *
0034:         * For work added by the HSQL Development Group:
0035:         *
0036:         * Copyright (c) 2001-2005, The HSQL Development Group
0037:         * All rights reserved.
0038:         *
0039:         * Redistribution and use in source and binary forms, with or without
0040:         * modification, are permitted provided that the following conditions are met:
0041:         *
0042:         * Redistributions of source code must retain the above copyright notice, this
0043:         * list of conditions and the following disclaimer.
0044:         *
0045:         * Redistributions in binary form must reproduce the above copyright notice,
0046:         * this list of conditions and the following disclaimer in the documentation
0047:         * and/or other materials provided with the distribution.
0048:         *
0049:         * Neither the name of the HSQL Development Group nor the names of its
0050:         * contributors may be used to endorse or promote products derived from this
0051:         * software without specific prior written permission.
0052:         *
0053:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0054:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0055:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0056:         * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0057:         * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0058:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0059:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0060:         * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0061:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0062:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0063:         * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0064:         */
0065:
0066:        package org.hsqldb;
0067:
0068:        import java.util.Locale;
0069:
0070:        import org.hsqldb.HsqlNameManager.HsqlName;
0071:        import org.hsqldb.lib.ArrayUtil;
0072:        import org.hsqldb.lib.HashMap;
0073:        import org.hsqldb.lib.HashMappedList;
0074:        import org.hsqldb.lib.HsqlArrayList;
0075:        import org.hsqldb.lib.IntKeyHashMap;
0076:        import org.hsqldb.lib.IntValueHashMap;
0077:        import org.hsqldb.lib.Iterator;
0078:        import org.hsqldb.lib.StringConverter;
0079:        import org.hsqldb.store.ValuePool;
0080:        import org.hsqldb.lib.HashSet;
0081:
0082:        // fredt@users 20020130 - patch 497872 by Nitin Chauhan - reordering for speed
0083:        // fredt@users 20020215 - patch 1.7.0 by fredt - support GROUP BY with more than one column
0084:        // fredt@users 20020215 - patch 1.7.0 by fredt - SQL standard quoted identifiers
0085:        // fredt@users 20020218 - patch 1.7.0 by fredt - DEFAULT keyword
0086:        // fredt@users 20020221 - patch 513005 by sqlbob@users - SELECT INTO types
0087:        // fredt@users 20020425 - patch 548182 by skitt@users - DEFAULT enhancement
0088:        // thertz@users 20020320 - patch 473613 by thertz - outer join condition bug
0089:        // fredt@users 20021229 - patch 1.7.2 by fredt - new solution for above
0090:        // fredt@users 20020420 - patch 523880 by leptipre@users - VIEW support
0091:        // fredt@users 20020525 - patch 559914 by fredt@users - SELECT INTO logging
0092:        // tony_lai@users 20021020 - patch 1.7.2 - improved aggregates and HAVING
0093:        // aggregate functions can now be used in expressions - HAVING supported
0094:        // kloska@users 20021030 - patch 1.7.2 - ON UPDATE CASCADE
0095:        // fredt@users 20021112 - patch 1.7.2 by Nitin Chauhan - use of switch
0096:        // rewrite of the majority of multiple if(){}else{} chains with switch(){}
0097:        // boucherb@users 20030705 - patch 1.7.2 - prepared statement support
0098:        // fredt@users 20030819 - patch 1.7.2 - EXTRACT({YEAR | MONTH | DAY | HOUR | MINUTE | SECOND } FROM datetime)
0099:        // fredt@users 20030820 - patch 1.7.2 - CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH(string)
0100:        // fredt@users 20030820 - patch 1.7.2 - POSITION(string IN string)
0101:        // fredt@users 20030820 - patch 1.7.2 - SUBSTRING(string FROM pos [FOR length])
0102:        // fredt@users 20030820 - patch 1.7.2 - TRIM({LEADING | TRAILING | BOTH} [<character>] FROM <string expression>)
0103:        // fredt@users 20030820 - patch 1.7.2 - CASE [expr] WHEN ... THEN ... [ELSE ...] END and its variants
0104:        // fredt@users 20030820 - patch 1.7.2 - NULLIF(expr,expr)
0105:        // fredt@users 20030820 - patch 1.7.2 - COALESCE(expr,expr,...)
0106:        // fredt@users 20031012 - patch 1.7.2 - improved scoping for column names in all areas
0107:        // boucherb@users 200403xx - patch 1.7.2 - added support for prepared SELECT INTO
0108:        // boucherb@users 200403xx - doc 1.7.2 - some
0109:        // thomasm@users 20041001 - patch 1.7.3 - BOOLEAN undefined handling
0110:        // fredt@users 20050220 - patch 1.8.0 - CAST with precision / scale
0111:        /* todo: fredt - implement remaining numeric value functions (SQL92 6.6)
0112:         *
0113:         * EXTRACT({TIMEZONE_HOUR | TIMEZONE_MINUTE} FROM {datetime | interval})
0114:         */
0115:
0116:        /**
0117:         * Responsible for parsing non-DDL statements.
0118:         *
0119:         * Extensively rewritten and extended in successive versions of HSQLDB.
0120:         *
0121:         * @author Thomas Mueller (Hypersonic SQL Group)
0122:         * @version 1.8.0
0123:         * @since Hypersonic SQL
0124:         */
0125:        class Parser {
0126:
0127:            private Database database;
0128:            private Tokenizer tokenizer;
0129:            private Session session;
0130:            private String sSchema;
0131:            private String sTable;
0132:            private String sToken;
0133:            private boolean wasQuoted;
0134:            private Object oData;
0135:            private int iType;
0136:            private int iToken;
0137:            private boolean compilingView;
0138:
0139:            //
0140:            private int subQueryLevel;
0141:            private HsqlArrayList subQueryList = new HsqlArrayList();
0142:
0143:            /**
0144:             *  Constructs a new Parser object with the given context.
0145:             *
0146:             * @param  db the Database instance against which to resolve named
0147:             *      database object references
0148:             * @param  t the token source from which to parse commands
0149:             * @param  session the connected context
0150:             */
0151:            Parser(Session session, Database db, Tokenizer t) {
0152:
0153:                database = db;
0154:                tokenizer = t;
0155:                this .session = session;
0156:            }
0157:
0158:            /**
0159:             *  sets a flag indicating the parser is used for compiling a view
0160:             */
0161:            void setCompilingView() {
0162:                compilingView = true;
0163:            }
0164:
0165:            /**
0166:             *  determines whether the parser is used for compiling a view
0167:             */
0168:            boolean isCompilingView() {
0169:                return compilingView;
0170:            }
0171:
0172:            /**
0173:             *  Resets this parse context with the given SQL character sequence.
0174:             *
0175:             * Internal structures are reset as though a new parser were created
0176:             * with the given sql and the originally specified database and session
0177:             *
0178:             * @param a new SQL character sequence to replace the current one
0179:             */
0180:            void reset(String sql) {
0181:
0182:                sTable = null;
0183:                sToken = null;
0184:                oData = null;
0185:
0186:                tokenizer.reset(sql);
0187:                subQueryList.clear();
0188:
0189:                subQueryLevel = 0;
0190:
0191:                parameters.clear();
0192:            }
0193:
0194:            /**
0195:             * Tests whether the parsing session has the given write access on the
0196:             * given Table object. <p>
0197:             *
0198:             * @param table the Table object to check
0199:             * @param userRight the numeric code of the right to check
0200:             * @throws HsqlException if the session user does not have the right
0201:             *      or the given Table object is simply not writable (e.g. is a
0202:             *      non-updateable View)
0203:             */
0204:            void checkTableWriteAccess(Table table, int userRight)
0205:                    throws HsqlException {
0206:
0207:                // session level user rights
0208:                session.checkReadWrite();
0209:
0210:                // object level user rights
0211:                session.check(table.getName(), userRight);
0212:
0213:                // object type
0214:                if (table.isView()) {
0215:                    throw Trace.error(Trace.NOT_A_TABLE, table.getName().name);
0216:                }
0217:
0218:                // object readonly
0219:                table.checkDataReadOnly();
0220:            }
0221:
0222:            /**
0223:             * Parses a comma-separated, right-bracket terminated list of column
0224:             * names. <p>
0225:             *
0226:             * @param db the Database instance whose name manager is to provide the
0227:             *      resulting HsqlName objects, when the full argument is true
0228:             * @param t the tokenizer representing the character sequence to be parsed
0229:             * @param full if true, generate a list of HsqlNames, else a list of
0230:             *  String objects
0231:             */
0232:            static HsqlArrayList getColumnNames(Database db, Table table,
0233:                    Tokenizer t, boolean full) throws HsqlException {
0234:
0235:                HsqlArrayList columns = new HsqlArrayList();
0236:
0237:                while (true) {
0238:                    if (full) {
0239:                        String token = t.getSimpleName();
0240:                        boolean quoted = t.wasQuotedIdentifier();
0241:                        HsqlName name = db.nameManager.newHsqlName(token,
0242:                                quoted);
0243:
0244:                        columns.add(name);
0245:                    } else {
0246:                        columns.add(t.getName());
0247:
0248:                        if (t.wasLongName()
0249:                                && !t.getLongNameFirst().equals(
0250:                                        table.getName().name)) {
0251:                            throw (Trace.error(Trace.TABLE_NOT_FOUND, t
0252:                                    .getLongNameFirst()));
0253:                        }
0254:                    }
0255:
0256:                    String token = t.getSimpleToken();
0257:
0258:                    if (token.equals(Token.T_COMMA)) {
0259:                        continue;
0260:                    }
0261:
0262:                    if (token.equals(Token.T_CLOSEBRACKET)) {
0263:                        break;
0264:                    }
0265:
0266:                    t.throwUnexpected();
0267:                }
0268:
0269:                return columns;
0270:            }
0271:
0272:            /**
0273:             * The SubQuery objects are added to the end of subquery list.
0274:             *
0275:             * When parsing the SELECT for a view, optional HsqlName[] array is used
0276:             * for view column aliases.
0277:             *
0278:             */
0279:            SubQuery parseSubquery(int brackets, HsqlName[] colNames,
0280:                    boolean resolveAll, int predicateType) throws HsqlException {
0281:
0282:                SubQuery sq;
0283:
0284:                sq = new SubQuery();
0285:
0286:                subQueryLevel++;
0287:
0288:                boolean canHaveOrder = predicateType == Expression.VIEW;
0289:                boolean canHaveLimit = predicateType == Expression.SELECT
0290:                        || predicateType == Expression.VIEW
0291:                        || predicateType == Expression.QUERY;
0292:                boolean limitWithOrder = predicateType == Expression.IN
0293:                        || predicateType == Expression.ALL
0294:                        || predicateType == Expression.ANY;
0295:                Select s = parseSelect(brackets, canHaveOrder, canHaveLimit,
0296:                        limitWithOrder, true);
0297:
0298:                sq.level = subQueryLevel;
0299:
0300:                subQueryLevel--;
0301:
0302:                boolean isResolved = s.resolveAll(session, resolveAll);
0303:
0304:                sq.select = s;
0305:                sq.isResolved = isResolved;
0306:
0307:                // it's not a problem that this table has not a unique name
0308:                HsqlName sqtablename = database.nameManager.newHsqlName(
0309:                        "SYSTEM_SUBQUERY", false);
0310:
0311:                sqtablename.schema = database.schemaManager.SYSTEM_SCHEMA_HSQLNAME;
0312:
0313:                Table table = new Table(database, sqtablename,
0314:                        Table.SYSTEM_SUBQUERY);
0315:
0316:                if (colNames != null) {
0317:                    if (colNames.length != s.iResultLen) {
0318:                        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
0319:                    }
0320:
0321:                    for (int i = 0; i < s.iResultLen; i++) {
0322:                        HsqlName name = colNames[i];
0323:
0324:                        s.exprColumns[i].setAlias(name.name, name.isNameQuoted);
0325:                    }
0326:                } else {
0327:                    for (int i = 0; i < s.iResultLen; i++) {
0328:                        String colname = s.exprColumns[i].getAlias();
0329:
0330:                        if (colname == null || colname.length() == 0) {
0331:
0332:                            // fredt - this does not guarantee the uniqueness of column
0333:                            // names but addColumns() will throw if names are not unique.
0334:                            colname = "COL_" + String.valueOf(i + 1);
0335:
0336:                            s.exprColumns[i].setAlias(colname, false);
0337:                        }
0338:                    }
0339:                }
0340:
0341:                table.addColumns(s);
0342:
0343:                boolean uniqueValues = predicateType == Expression.EXISTS
0344:                        || predicateType == Expression.IN
0345:                        || predicateType == Expression.ALL
0346:                        || predicateType == Expression.ANY;
0347:                int[] pcol = null;
0348:
0349:                if (uniqueValues) {
0350:                    pcol = new int[s.iResultLen];
0351:
0352:                    ArrayUtil.fillSequence(pcol);
0353:                }
0354:
0355:                table.createPrimaryKey(pcol);
0356:
0357:                sq.table = table;
0358:                sq.uniqueRows = uniqueValues;
0359:
0360:                subQueryList.add(sq);
0361:
0362:                return sq;
0363:            }
0364:
0365:            SubQuery getViewSubquery(View v) {
0366:
0367:                SubQuery sq = v.viewSubQuery;
0368:
0369:                for (int i = 0; i < v.viewSubqueries.length; i++) {
0370:                    subQueryList.add(v.viewSubqueries[i]);
0371:                }
0372:
0373:                return sq;
0374:            }
0375:
0376:            /**
0377:             *  Constructs and returns a Select object.
0378:             *
0379:             * @param canHaveOrder whether the SELECT being parsed can have an ORDER BY
0380:             * @param canHaveLimit whether LIMIT without ORDER BY is allowed
0381:             * @param limitWithOrder whether LIMIT is allowed only with ORDER BY
0382:             * @param isMain whether the SELECT being parsed is the first
0383:             * select statement in the set
0384:             * @return a new Select object
0385:             * @throws  HsqlException if a parsing error occurs
0386:             */
0387:            Select parseSelect(int brackets, boolean canHaveOrder,
0388:                    boolean canHaveLimit, boolean limitWithOrder, boolean isMain)
0389:                    throws HsqlException {
0390:
0391:                Select select = new Select();
0392:                String token = tokenizer.getString();
0393:
0394:                if (canHaveLimit || limitWithOrder) {
0395:                    if (tokenizer.wasThis(Token.T_LIMIT)
0396:                            || tokenizer.wasThis(Token.T_TOP)) {
0397:                        parseLimit(token, select, false);
0398:
0399:                        token = tokenizer.getString();
0400:                    }
0401:                }
0402:
0403:                if (tokenizer.wasThis(Token.T_DISTINCT)) {
0404:                    select.isDistinctSelect = true;
0405:                } else if (tokenizer.wasThis(Token.T_ALL)) {
0406:                } else {
0407:                    tokenizer.back();
0408:                }
0409:
0410:                // parse column list
0411:                HsqlArrayList vcolumn = new HsqlArrayList();
0412:
0413:                do {
0414:                    int expPos = tokenizer.getPosition();
0415:                    Expression e = parseExpression();
0416:
0417:                    if (isCompilingView()) {
0418:                        if (e.getType() == Expression.ASTERISK) {
0419:                            if (select.asteriskPositions == null) {
0420:                                select.asteriskPositions = new IntKeyHashMap();
0421:                            }
0422:
0423:                            // remember the position of the asterisk. For the moment, just
0424:                            // remember the expression, so it can later be found and replaced
0425:                            // with the concrete column list
0426:                            select.asteriskPositions.put(expPos, e);
0427:                        }
0428:                    }
0429:
0430:                    token = tokenizer.getString();
0431:
0432:                    if (tokenizer.wasThis(Token.T_AS)) {
0433:                        e.setAlias(tokenizer.getSimpleName(), tokenizer
0434:                                .wasQuotedIdentifier());
0435:
0436:                        token = tokenizer.getString();
0437:                    } else if (tokenizer.wasSimpleName()) {
0438:                        e.setAlias(token, tokenizer.wasQuotedIdentifier());
0439:
0440:                        token = tokenizer.getString();
0441:                    }
0442:
0443:                    vcolumn.add(e);
0444:                } while (tokenizer.wasThis(Token.T_COMMA));
0445:
0446:                if (token.equals(Token.T_INTO)) {
0447:                    boolean getname = true;
0448:
0449:                    token = tokenizer.getString();
0450:                    select.intoType = database.getDefaultTableType();
0451:
0452:                    if (tokenizer.wasSimpleToken()) {
0453:                        switch (Token.get(token)) {
0454:
0455:                        case Token.CACHED:
0456:                            select.intoType = Table.CACHED_TABLE;
0457:                            break;
0458:
0459:                        case Token.TEMP:
0460:                            select.intoType = Table.TEMP_TABLE;
0461:                            break;
0462:
0463:                        case Token.TEXT:
0464:                            select.intoType = Table.TEXT_TABLE;
0465:                            break;
0466:
0467:                        case Token.MEMORY:
0468:                            select.intoType = Table.MEMORY_TABLE;
0469:                            break;
0470:
0471:                        default:
0472:                            getname = false;
0473:                            break;
0474:                        }
0475:
0476:                        if (getname) {
0477:                            token = tokenizer.getName();
0478:                        }
0479:                    }
0480:
0481:                    if (!tokenizer.wasName()) {
0482:                        tokenizer.throwUnexpected();
0483:                    }
0484:
0485:                    select.sIntoTable = database.nameManager.newHsqlName(token,
0486:                            tokenizer.wasQuotedIdentifier());
0487:                    select.sIntoTable.schema = session
0488:                            .getSchemaHsqlName(tokenizer.getLongNameFirst());
0489:                    token = tokenizer.getString();
0490:                }
0491:
0492:                tokenizer.matchThis(Token.T_FROM);
0493:
0494:                Expression condition = null;
0495:
0496:                // parse table list
0497:                HsqlArrayList vfilter = new HsqlArrayList();
0498:
0499:                vfilter.add(parseTableFilter(false));
0500:
0501:                while (true) {
0502:                    token = tokenizer.getString();
0503:
0504:                    boolean cross = false;
0505:
0506:                    if (tokenizer.wasThis(Token.T_INNER)) {
0507:                        tokenizer.getThis(Token.T_JOIN);
0508:
0509:                        token = Token.T_JOIN;
0510:                    } else if (tokenizer.wasThis(Token.T_CROSS)) {
0511:                        tokenizer.getThis(Token.T_JOIN);
0512:
0513:                        token = Token.T_JOIN;
0514:                        cross = true;
0515:                    }
0516:
0517:                    if (token.equals(Token.T_LEFT)
0518:                            && !tokenizer.wasQuotedIdentifier()) {
0519:                        tokenizer.isGetThis(Token.T_OUTER);
0520:                        tokenizer.getThis(Token.T_JOIN);
0521:
0522:                        TableFilter tf = parseTableFilter(true);
0523:
0524:                        vfilter.add(tf);
0525:                        tokenizer.getThis(Token.T_ON);
0526:
0527:                        Expression newcondition = parseExpression();
0528:
0529:                        newcondition.checkTables(vfilter);
0530:
0531:                        condition = addJoinCondition(condition, newcondition,
0532:                                tf, true);
0533:
0534:                        // MarcH HuugO RIGHT JOIN SUPPORT
0535:                    } else if (token.equals(Token.T_RIGHT)
0536:                            && !tokenizer.wasQuotedIdentifier()) {
0537:                        tokenizer.isGetThis(Token.T_OUTER);
0538:                        tokenizer.getThis(Token.T_JOIN);
0539:
0540:                        // this object is not an outerjoin, the next object is an outerjoin
0541:                        TableFilter tf = parseTableFilter(false);
0542:
0543:                        // insert new condition as first element in a new vfilter (nvfilter), copy the content of vfilter and rename nvfilter back to vfilter.
0544:                        HsqlArrayList nvfilter = new HsqlArrayList();
0545:
0546:                        nvfilter.add(tf);
0547:                        nvfilter.addAll(vfilter);
0548:
0549:                        vfilter = nvfilter;
0550:
0551:                        // set isOuterJoin correct
0552:                        ((TableFilter) vfilter.get(1)).isOuterJoin = true;
0553:
0554:                        tokenizer.getThis(Token.T_ON);
0555:
0556:                        Expression newcondition = parseExpression();
0557:
0558:                        newcondition.checkTables(vfilter);
0559:
0560:                        condition = addJoinCondition(condition, newcondition,
0561:                                ((TableFilter) vfilter.get(1)), true);
0562:                    } else if (tokenizer.wasThis(Token.T_JOIN)) {
0563:                        vfilter.add(parseTableFilter(false));
0564:
0565:                        if (!cross) {
0566:                            tokenizer.getThis(Token.T_ON);
0567:
0568:                            Expression newcondition = parseExpression();
0569:
0570:                            newcondition.checkTables(vfilter);
0571:
0572:                            condition = addJoinCondition(condition,
0573:                                    newcondition, null, false);
0574:                        }
0575:                    } else if (tokenizer.wasThis(Token.T_COMMA)) {
0576:                        vfilter.add(parseTableFilter(false));
0577:                    } else {
0578:                        tokenizer.back();
0579:
0580:                        break;
0581:                    }
0582:                }
0583:
0584:                resolveSelectTableFilter(select, vcolumn, vfilter);
0585:
0586:                // where
0587:                token = tokenizer.getString();
0588:
0589:                if (tokenizer.wasThis(Token.T_WHERE)) {
0590:                    Expression newcondition = parseExpression();
0591:
0592:                    condition = addCondition(condition, newcondition);
0593:                    token = tokenizer.getString();
0594:                }
0595:
0596:                select.queryCondition = condition;
0597:
0598:                // group by
0599:                if (tokenizer.wasThis(Token.T_GROUP)) {
0600:                    tokenizer.getThis(Token.T_BY);
0601:
0602:                    int len = 0;
0603:
0604:                    do {
0605:                        Expression e = parseExpression();
0606:
0607:                        vcolumn.add(e);
0608:
0609:                        token = tokenizer.getString();
0610:
0611:                        len++;
0612:                    } while (tokenizer.wasThis(Token.T_COMMA));
0613:
0614:                    select.iGroupLen = len;
0615:                }
0616:
0617:                // having
0618:                if (tokenizer.wasThis(Token.T_HAVING)) {
0619:                    select.iHavingLen = 1;
0620:                    select.havingCondition = parseExpression();
0621:                    token = tokenizer.getString();
0622:
0623:                    vcolumn.add(select.havingCondition);
0624:                }
0625:
0626:                if (isMain || limitWithOrder) {
0627:                    if (tokenizer.wasThis(Token.T_ORDER)) {
0628:                        tokenizer.getThis(Token.T_BY);
0629:                        parseOrderBy(select, vcolumn);
0630:
0631:                        token = tokenizer.getString();
0632:                    }
0633:
0634:                    if (tokenizer.wasThis(Token.T_LIMIT)) {
0635:                        parseLimit(token, select, true);
0636:
0637:                        token = tokenizer.getString();
0638:                    }
0639:                }
0640:
0641:                boolean closebrackets = false;
0642:
0643:                if (brackets > 0 && token.equals(Token.T_CLOSEBRACKET)) {
0644:                    closebrackets = true;
0645:                    brackets -= parseCloseBrackets(brackets - 1) + 1;
0646:                    token = tokenizer.getString();
0647:                }
0648:
0649:                select.unionDepth = brackets;
0650:
0651:                // checks for ORDER and LIMIT
0652:                if (!(isMain || closebrackets)) {
0653:                    limitWithOrder = false;
0654:                }
0655:
0656:                boolean hasOrder = select.iOrderLen != 0;
0657:                boolean hasLimit = select.limitCondition != null;
0658:
0659:                if (limitWithOrder) {
0660:                    if (hasLimit && !hasOrder) {
0661:                        throw Trace.error(Trace.ORDER_LIMIT_REQUIRED);
0662:                    }
0663:                } else {
0664:                    if (hasOrder && !canHaveOrder) {
0665:                        throw Trace.error(Trace.INVALID_ORDER_BY);
0666:                    }
0667:
0668:                    if (hasLimit && !canHaveLimit) {
0669:                        throw Trace.error(Trace.INVALID_LIMIT);
0670:                    }
0671:                }
0672:
0673:                int unionType = parseUnion(token);
0674:
0675:                if (unionType != Select.NOUNION) {
0676:                    boolean openbracket = false;
0677:
0678:                    select.unionType = unionType;
0679:
0680:                    if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
0681:                        openbracket = true;
0682:                        brackets += parseOpenBrackets() + 1;
0683:                    }
0684:
0685:                    tokenizer.getThis(Token.T_SELECT);
0686:
0687:                    // accept ORDRY BY with LIMIT when in brackets
0688:                    select.unionSelect = parseSelect(brackets, false, false,
0689:                            openbracket, false);
0690:                    token = tokenizer.getString();
0691:                }
0692:
0693:                if (isMain && (canHaveOrder || limitWithOrder)
0694:                        && select.iOrderLen == 0) {
0695:                    if (tokenizer.wasThis(Token.T_ORDER)) {
0696:                        tokenizer.getThis(Token.T_BY);
0697:                        parseOrderBy(select, vcolumn);
0698:
0699:                        token = tokenizer.getString();
0700:                        select.sortUnion = true;
0701:                    }
0702:
0703:                    if (tokenizer.wasThis(Token.T_LIMIT)) {
0704:                        parseLimit(token, select, true);
0705:
0706:                        token = tokenizer.getString();
0707:                    }
0708:                }
0709:
0710:                tokenizer.back();
0711:
0712:                if (isMain) {
0713:                    select.prepareUnions();
0714:                }
0715:
0716:                int len = vcolumn.size();
0717:
0718:                select.exprColumns = new Expression[len];
0719:
0720:                vcolumn.toArray(select.exprColumns);
0721:
0722:                return select;
0723:            }
0724:
0725:            /**
0726:             * Parses the given token and any further tokens in tokenizer to return
0727:             * any UNION or other set operation ID.
0728:             */
0729:            int parseUnion(String token) throws HsqlException {
0730:
0731:                int unionType = Select.NOUNION;
0732:
0733:                if (tokenizer.wasSimpleToken()) {
0734:                    switch (Token.get(token)) {
0735:
0736:                    case Token.UNION:
0737:                        token = tokenizer.getSimpleToken();
0738:
0739:                        if (token.equals(Token.T_ALL)) {
0740:                            unionType = Select.UNIONALL;
0741:                        } else if (token.equals(Token.T_DISTINCT)) {
0742:                            unionType = Select.UNION;
0743:                        } else {
0744:                            unionType = Select.UNION;
0745:
0746:                            tokenizer.back();
0747:                        }
0748:                        break;
0749:
0750:                    case Token.INTERSECT:
0751:                        tokenizer.isGetThis(Token.T_DISTINCT);
0752:
0753:                        unionType = Select.INTERSECT;
0754:                        break;
0755:
0756:                    case Token.EXCEPT:
0757:                    case Token.MINUS:
0758:                        tokenizer.isGetThis(Token.T_DISTINCT);
0759:
0760:                        unionType = Select.EXCEPT;
0761:                        break;
0762:
0763:                    default:
0764:                        break;
0765:                    }
0766:                }
0767:
0768:                return unionType;
0769:            }
0770:
0771:            // fredt@users 20011010 - patch 471710 by fredt - LIMIT rewritten
0772:            // SELECT LIMIT n m DISTINCT ... queries and error message
0773:            // "SELECT LIMIT n m ..." creates the result set for the SELECT statement then
0774:            // discards the first n rows and returns m rows of the remaining result set
0775:            // "SELECT LIMIT 0 m" is equivalent to "SELECT TOP m" or "SELECT FIRST m"
0776:            // in other RDBMS's
0777:            // "SELECT LIMIT n 0" discards the first n rows and returns the remaining rows
0778:            // fredt@users 20020225 - patch 456679 by hiep256 - TOP keyword
0779:            private void parseLimit(String token, Select select, boolean isEnd)
0780:                    throws HsqlException {
0781:
0782:                if (select.limitCondition != null) {
0783:                    return;
0784:                }
0785:
0786:                Expression e1 = null;
0787:                Expression e2;
0788:                boolean islimit = false;
0789:
0790:                if (isEnd) {
0791:                    if (token.equals(Token.T_LIMIT)) {
0792:                        islimit = true;
0793:
0794:                        read();
0795:
0796:                        e2 = readTerm();
0797:
0798:                        if (sToken.equals(Token.T_OFFSET)) {
0799:                            read();
0800:
0801:                            e1 = readTerm();
0802:                        }
0803:
0804:                        tokenizer.back();
0805:                    } else {
0806:                        return;
0807:                    }
0808:                } else if (token.equals(Token.T_LIMIT)) {
0809:                    read();
0810:
0811:                    e1 = readTerm();
0812:                    e2 = readTerm();
0813:                    islimit = true;
0814:
0815:                    tokenizer.back();
0816:                } else if (token.equals(Token.T_TOP)) {
0817:                    read();
0818:
0819:                    e2 = readTerm();
0820:
0821:                    tokenizer.back();
0822:                } else {
0823:                    return;
0824:                }
0825:
0826:                if (e1 == null) {
0827:                    e1 = new Expression(Types.INTEGER, ValuePool.getInt(0));
0828:                }
0829:
0830:                if (e1.isParam()
0831:                        || (e1.getType() == Expression.VALUE
0832:                                && e1.getDataType() == Types.INTEGER
0833:                                && e1.getValue(null) != null && ((Integer) e1
0834:                                .getValue(null)).intValue() >= 0)) {
0835:                    if (e2.isParam()
0836:                            || (e2.getType() == Expression.VALUE
0837:                                    && e2.getDataType() == Types.INTEGER
0838:                                    && e2.getValue(null) != null && ((Integer) e2
0839:                                    .getValue(null)).intValue() >= 0)) {
0840:
0841:                        // necessary for params
0842:                        e1.setDataType(Types.INTEGER);
0843:                        e2.setDataType(Types.INTEGER);
0844:
0845:                        select.limitCondition = new Expression(
0846:                                Expression.LIMIT, e1, e2);
0847:
0848:                        return;
0849:                    }
0850:                }
0851:
0852:                int messageid = islimit ? Trace.INVALID_LIMIT_EXPRESSION
0853:                        : Trace.INVALID_TOP_EXPRESSION;
0854:
0855:                throw Trace.error(Trace.WRONG_DATA_TYPE, messageid);
0856:            }
0857:
0858:            private void parseOrderBy(Select select, HsqlArrayList vcolumn)
0859:                    throws HsqlException {
0860:
0861:                String token;
0862:                int len = 0;
0863:
0864:                do {
0865:                    Expression e = parseExpression();
0866:
0867:                    e = resolveOrderByExpression(e, select, vcolumn);
0868:                    token = tokenizer.getString();
0869:
0870:                    if (token.equals(Token.T_DESC)) {
0871:                        e.setDescending();
0872:
0873:                        token = tokenizer.getString();
0874:                    } else if (token.equals(Token.T_ASC)) {
0875:                        token = tokenizer.getString();
0876:                    }
0877:
0878:                    vcolumn.add(e);
0879:
0880:                    len++;
0881:                } while (token.equals(Token.T_COMMA));
0882:
0883:                tokenizer.back();
0884:
0885:                select.iOrderLen = len;
0886:            }
0887:
0888:            private void resolveSelectTableFilter(Select select,
0889:                    HsqlArrayList vcolumn, HsqlArrayList vfilter)
0890:                    throws HsqlException {
0891:
0892:                int colcount;
0893:                TableFilter[] filters = new TableFilter[vfilter.size()];
0894:
0895:                vfilter.toArray(filters);
0896:
0897:                select.tFilter = filters;
0898:
0899:                // expand [table.]* columns
0900:                colcount = vcolumn.size();
0901:
0902:                for (int pos = 0; pos < colcount;) {
0903:                    Expression e = (Expression) (vcolumn.get(pos));
0904:
0905:                    if (e.getType() == Expression.ASTERISK) {
0906:                        vcolumn.remove(pos);
0907:
0908:                        colcount = vcolumn.size();
0909:
0910:                        String tablename = e.getTableName();
0911:                        int oldPos = pos;
0912:
0913:                        if (tablename == null) {
0914:                            for (int i = 0; i < filters.length; i++) {
0915:                                pos = addFilterColumns(filters[i], vcolumn, pos);
0916:                                colcount = vcolumn.size();
0917:                            }
0918:                        } else {
0919:                            TableFilter f = e.findTableFilter(filters);
0920:
0921:                            if (f == null) {
0922:                                throw Trace.error(Trace.TABLE_NOT_FOUND,
0923:                                        tablename);
0924:                            }
0925:
0926:                            pos = addFilterColumns(f, vcolumn, pos);
0927:                            colcount = vcolumn.size();
0928:                        }
0929:
0930:                        if (isCompilingView()) {
0931:
0932:                            // find this expression's position in the Select's asterisk list
0933:                            boolean foundAsteriskPos = false;
0934:                            Iterator expSearch = select.asteriskPositions
0935:                                    .keySet().iterator();
0936:
0937:                            while (expSearch.hasNext()) {
0938:                                int expPos = expSearch.nextInt();
0939:
0940:                                if (e == select.asteriskPositions.get(expPos)) {
0941:
0942:                                    // compile the complete column list which later is to replace the asterisk
0943:                                    StringBuffer completeColList = new StringBuffer();
0944:
0945:                                    for (int col = oldPos; col < pos; ++col) {
0946:                                        Expression resolvedColExpr = (Expression) (vcolumn
0947:                                                .get(col));
0948:
0949:                                        completeColList.append(resolvedColExpr
0950:                                                .getColumnDDL());
0951:
0952:                                        if (col < pos - 1) {
0953:                                            completeColList.append(", ");
0954:                                        }
0955:                                    }
0956:
0957:                                    select.asteriskPositions.put(expPos,
0958:                                            completeColList.toString());
0959:
0960:                                    foundAsteriskPos = true;
0961:
0962:                                    break;
0963:                                }
0964:                            }
0965:
0966:                            Trace.doAssert(foundAsteriskPos);
0967:                        }
0968:                    } else {
0969:                        if (e.getFilter() == null) {
0970:                            for (int i = 0; i < filters.length; i++) {
0971:                                e.resolveTables(filters[i]);
0972:                            }
0973:                        }
0974:
0975:                        pos++;
0976:                    }
0977:                }
0978:
0979:                for (int i = 0; i < colcount; i++) {
0980:                    Expression e = (Expression) (vcolumn.get(i));
0981:
0982:                    e.resolveTypes(session);
0983:                }
0984:
0985:                select.iResultLen = colcount;
0986:            }
0987:
0988:            /**
0989:             * Add all columns of a table filter to list of columns
0990:             */
0991:            int addFilterColumns(TableFilter filter, HsqlArrayList columnList,
0992:                    int position) throws HsqlException {
0993:
0994:                Table table = filter.getTable();
0995:                int count = table.getColumnCount();
0996:
0997:                for (int i = 0; i < count; i++) {
0998:                    Expression e = new Expression(filter, table.getColumn(i));
0999:
1000:                    if (isCompilingView()) {
1001:                        e.resolveTables(filter);
1002:                    }
1003:
1004:                    columnList.add(position++, e);
1005:                }
1006:
1007:                return position;
1008:            }
1009:
1010:            /**
1011:             * Resolves an ORDER BY Expression, returning the column Expression object
1012:             * to which it refers if it is an alias or column index. <p>
1013:             *
1014:             * If select is a SET QUERY, then only column indexes or names in the first
1015:             * query are allowed.
1016:             *
1017:             * @param  e                          search column expression
1018:             * @param  vcolumn                    list of columns
1019:             * @param  union                      is select a union
1020:             * @return                            new or the same expression
1021:             * @throws HsqlException if an ambiguous reference to an alias or
1022:             *      non-integer column index is encountered
1023:             */
1024:            private static Expression resolveOrderByExpression(Expression e,
1025:                    Select select, HsqlArrayList vcolumn) throws HsqlException {
1026:
1027:                int visiblecols = select.iResultLen;
1028:                boolean union = select.unionSelect != null;
1029:
1030:                if (e.getType() == Expression.VALUE) {
1031:                    return resolveOrderByColumnIndex(e, vcolumn, visiblecols);
1032:                }
1033:
1034:                if (e.getType() != Expression.COLUMN) {
1035:                    if (union) {
1036:                        throw Trace.error(Trace.INVALID_ORDER_BY);
1037:                    }
1038:
1039:                    return e;
1040:                }
1041:
1042:                String ecolname = e.getColumnName();
1043:                String etablename = e.getTableName();
1044:
1045:                for (int i = 0, size = visiblecols; i < size; i++) {
1046:                    Expression colexpr = (Expression) vcolumn.get(i);
1047:                    String colalias = colexpr.getDefinedAlias();
1048:                    String colname = colexpr.getColumnName();
1049:                    String tablename = colexpr.getTableName();
1050:                    String filtername = colexpr.getFilterTableName();
1051:
1052:                    if ((ecolname.equals(colalias) || ecolname.equals(colname))
1053:                            && (etablename == null
1054:                                    || etablename.equals(tablename) || etablename
1055:                                    .equals(filtername))) {
1056:                        colexpr.joinedTableColumnIndex = i;
1057:
1058:                        return colexpr;
1059:                    }
1060:                }
1061:
1062:                if (union) {
1063:                    throw Trace.error(Trace.INVALID_ORDER_BY, ecolname);
1064:                }
1065:
1066:                return e;
1067:            }
1068:
1069:            private static Expression resolveOrderByColumnIndex(Expression e,
1070:                    HsqlArrayList vcolumn, int visiblecols)
1071:                    throws HsqlException {
1072:
1073:                // order by 1,2,3
1074:                if (e.getDataType() == Types.INTEGER) {
1075:                    int i = ((Integer) e.getValue(null)).intValue();
1076:
1077:                    if (0 < i && i <= visiblecols) {
1078:                        Expression colexpr = (Expression) vcolumn.get(i - 1);
1079:
1080:                        colexpr.joinedTableColumnIndex = i - 1;
1081:
1082:                        return colexpr;
1083:                    }
1084:                }
1085:
1086:                throw Trace.error(Trace.INVALID_ORDER_BY);
1087:            }
1088:
1089:            private TableFilter parseSimpleTableFilter(int type)
1090:                    throws HsqlException {
1091:
1092:                String alias = null;
1093:                String token = tokenizer.getName();
1094:                String schema = session.getSchemaName(tokenizer
1095:                        .getLongNameFirst());
1096:                Table table = database.schemaManager.getTable(session, token,
1097:                        schema);
1098:
1099:                checkTableWriteAccess(table, type);
1100:
1101:                //
1102:                token = tokenizer.getString();
1103:
1104:                if (token.equals(Token.T_AS)) {
1105:                    alias = tokenizer.getSimpleName();
1106:                } else if (tokenizer.wasSimpleName()) {
1107:                    alias = token;
1108:                } else {
1109:                    tokenizer.back();
1110:                }
1111:
1112:                return new TableFilter(table, alias, null, false);
1113:            }
1114:
1115:            /**
1116:             * Retrieves a TableFilter object newly constructed from the current
1117:             * parse context. <p>
1118:             *
1119:             * @param  outerjoin if the filter is to back an outer join
1120:             * @return a newly constructed TableFilter object
1121:             * @throws  HsqlException if a parsing error occurs
1122:             */
1123:            private TableFilter parseTableFilter(boolean outerjoin)
1124:                    throws HsqlException {
1125:
1126:                Table t = null;
1127:                SubQuery sq = null;
1128:                String sAlias = null;
1129:                HashMappedList columnList = null;
1130:
1131:                if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1132:                    int brackets = parseOpenBrackets();
1133:
1134:                    tokenizer.getThis(Token.T_SELECT);
1135:
1136:                    // fredt - not correlated - a joined subquery table must resolve fully
1137:                    sq = parseSubquery(brackets, null, true, Expression.QUERY);
1138:
1139:                    tokenizer.getThis(Token.T_CLOSEBRACKET);
1140:
1141:                    t = sq.table;
1142:                } else {
1143:                    String token = tokenizer.getName();
1144:                    String schema = session.getSchemaName(tokenizer
1145:                            .getLongNameFirst());
1146:
1147:                    t = database.schemaManager.getTable(session, token, schema);
1148:
1149:                    session.check(t.getName(), UserManager.SELECT);
1150:
1151:                    if (t.isView()) {
1152:                        sq = getViewSubquery((View) t);
1153:                        sq.select = ((View) t).viewSelect;
1154:                        t = sq.table;
1155:                        sAlias = token;
1156:                    }
1157:                }
1158:
1159:                // fredt - we removed LEFT from the list of reserved words in Tokenizer
1160:                // to allow LEFT() to work. Thus wasName() will return true for LEFT
1161:                // and we check separately for this token
1162:                String token = tokenizer.getString();
1163:
1164:                if (tokenizer.wasLongName()) {
1165:                    tokenizer.throwUnexpected();
1166:                }
1167:
1168:                if ((token.equals(Token.T_LEFT) || token.equals(Token.T_RIGHT))
1169:                        && !tokenizer.wasQuotedIdentifier()) {
1170:                    tokenizer.back();
1171:                } else if (token.equals(Token.T_AS)
1172:                        && !tokenizer.wasQuotedIdentifier()) {
1173:                    sAlias = tokenizer.getSimpleName();
1174:
1175:                    if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1176:                        tokenizer.back();
1177:
1178:                        columnList = parseColumnList();
1179:                    }
1180:                } else if (tokenizer.wasSimpleName()) {
1181:                    sAlias = token;
1182:
1183:                    if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1184:                        tokenizer.back();
1185:
1186:                        columnList = parseColumnList();
1187:                    }
1188:                } else {
1189:                    tokenizer.back();
1190:                }
1191:
1192:                if (columnList != null
1193:                        && t.getColumnCount() != columnList.size()) {
1194:                    throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
1195:                }
1196:
1197:                return new TableFilter(t, sAlias, columnList, outerjoin);
1198:            }
1199:
1200:            /**
1201:             *  Add a condition from the WHERE clause.
1202:             *
1203:             * @param  e1
1204:             * @param  e2
1205:             * @return
1206:             */
1207:            private static Expression addCondition(Expression e1, Expression e2) {
1208:
1209:                if (e1 == null) {
1210:                    return e2;
1211:                } else if (e2 == null) {
1212:                    return e1;
1213:                } else {
1214:                    return new Expression(Expression.AND, e1, e2);
1215:                }
1216:            }
1217:
1218:            /**
1219:             *  Conjuntively adds a condition from the JOIN table ON clause.
1220:             *
1221:             * @param  e1 an existing condition with which e2 is to be combined
1222:             *      in order to form a new conjunction
1223:             * @param  e2 the new condition
1224:             * @param tf the table filter that should become e2's join
1225:             *      table filter
1226:             * @param outer true if join is outer
1227:             * @throws HsqlException if e2 responds that it cannot participate
1228:             *      in the join
1229:             * @return a new Expression object; the conjunction of e1 and e2
1230:             */
1231:            private static Expression addJoinCondition(Expression e1,
1232:                    Expression e2, TableFilter tf, boolean outer)
1233:                    throws HsqlException {
1234:
1235:                if (!e2.setForJoin(tf, outer)) {
1236:                    throw Trace.error(Trace.OUTER_JOIN_CONDITION);
1237:                }
1238:
1239:                return addCondition(e1, e2);
1240:            }
1241:
1242:            /**
1243:             *  Method declaration
1244:             *
1245:             * @return the Expression resulting from the parse
1246:             * @throws  HsqlException
1247:             */
1248:            Expression parseExpression() throws HsqlException {
1249:
1250:                read();
1251:
1252:                Expression r = readOr();
1253:
1254:                tokenizer.back();
1255:
1256:                return r;
1257:            }
1258:
1259:            private Expression readAggregate() throws HsqlException {
1260:
1261:                boolean distinct = false;
1262:                boolean all = false;
1263:                int type = iToken;
1264:
1265:                read();
1266:
1267:                String token = tokenizer.getString();
1268:
1269:                if (token.equals(Token.T_DISTINCT)) {
1270:                    distinct = true;
1271:                } else if (token.equals(Token.T_ALL)) {
1272:                    all = true;
1273:                } else {
1274:                    tokenizer.back();
1275:                }
1276:
1277:                readThis(Expression.OPEN);
1278:
1279:                Expression s = readOr();
1280:
1281:                readThis(Expression.CLOSE);
1282:
1283:                if ((all || distinct)
1284:                        && (type == Expression.STDDEV_POP
1285:                                || type == Expression.STDDEV_SAMP
1286:                                || type == Expression.VAR_POP || type == Expression.VAR_SAMP)) {
1287:                    throw Trace.error(Trace.INVALID_FUNCTION_ARGUMENT);
1288:                }
1289:
1290:                Expression aggregateExp = new Expression(type, s, null);
1291:
1292:                aggregateExp.setDistinctAggregate(distinct);
1293:
1294:                return aggregateExp;
1295:            }
1296:
1297:            /**
1298:             *  Method declaration
1299:             *
1300:             * @return a disjuntion, possibly degenerate
1301:             * @throws  HsqlException
1302:             */
1303:            private Expression readOr() throws HsqlException {
1304:
1305:                Expression r = readAnd();
1306:
1307:                while (iToken == Expression.OR) {
1308:                    int type = iToken;
1309:                    Expression a = r;
1310:
1311:                    read();
1312:
1313:                    r = new Expression(type, a, readAnd());
1314:                }
1315:
1316:                return r;
1317:            }
1318:
1319:            /**
1320:             *  Method declaration
1321:             *
1322:             * @return a conjunction, possibly degenerate
1323:             * @throws  HsqlException
1324:             */
1325:            private Expression readAnd() throws HsqlException {
1326:
1327:                Expression r = readCondition();
1328:
1329:                while (iToken == Expression.AND) {
1330:                    int type = iToken;
1331:                    Expression a = r;
1332:
1333:                    read();
1334:
1335:                    r = new Expression(type, a, readCondition());
1336:                }
1337:
1338:                return r;
1339:            }
1340:
1341:            /**
1342:             *  Method declaration
1343:             *
1344:             * @return a predicate, possibly composite
1345:             * @throws  HsqlException
1346:             */
1347:            private Expression readCondition() throws HsqlException {
1348:
1349:                switch (iToken) {
1350:
1351:                case Expression.NOT: {
1352:                    int type = iToken;
1353:
1354:                    read();
1355:
1356:                    return new Expression(type, readCondition(), null);
1357:                }
1358:                case Expression.EXISTS: {
1359:                    int type = iToken;
1360:
1361:                    read();
1362:                    readThis(Expression.OPEN);
1363:
1364:                    int brackets = 0;
1365:
1366:                    if (iToken == Expression.OPEN) {
1367:                        brackets += parseOpenBrackets() + 1;
1368:
1369:                        read();
1370:                    }
1371:
1372:                    Trace.check(iToken == Expression.SELECT,
1373:                            Trace.UNEXPECTED_TOKEN);
1374:
1375:                    SubQuery sq = parseSubquery(brackets, null, false,
1376:                            Expression.EXISTS);
1377:                    Expression s = new Expression(sq);
1378:
1379:                    read();
1380:                    readThis(Expression.CLOSE);
1381:
1382:                    return new Expression(type, s, null);
1383:                }
1384:                default: {
1385:                    Expression a = readConcat();
1386:
1387:                    if (iToken == Expression.IS) {
1388:                        read();
1389:
1390:                        boolean not;
1391:
1392:                        if (iToken == Expression.NOT) {
1393:                            not = true;
1394:
1395:                            read();
1396:                        } else {
1397:                            not = false;
1398:                        }
1399:
1400:                        Trace.check(
1401:                                iToken == Expression.VALUE && oData == null,
1402:                                Trace.UNEXPECTED_TOKEN);
1403:                        read();
1404:
1405:                        // TODO: the TableFilter needs a right hand side to avoid null pointer exceptions...
1406:                        a = new Expression(Expression.IS_NULL, a,
1407:                                new Expression(Types.NULL, null));
1408:
1409:                        if (not) {
1410:                            a = new Expression(Expression.NOT, a, null);
1411:                        }
1412:
1413:                        return a;
1414:                    }
1415:
1416:                    boolean not = false;
1417:
1418:                    if (iToken == Expression.NOT) {
1419:                        not = true;
1420:
1421:                        read();
1422:                    }
1423:
1424:                    switch (iToken) {
1425:
1426:                    case Expression.LIKE: {
1427:                        a = parseLikePredicate(a);
1428:
1429:                        break;
1430:                    }
1431:                    case Expression.BETWEEN: {
1432:                        a = parseBetweenPredicate(a);
1433:
1434:                        break;
1435:                    }
1436:                    case Expression.IN: {
1437:                        a = this .parseInPredicate(a);
1438:
1439:                        break;
1440:                    }
1441:                    default: {
1442:                        Trace.check(!not, Trace.UNEXPECTED_TOKEN);
1443:
1444:                        if (Expression.isCompare(iToken)) {
1445:                            int type = iToken;
1446:
1447:                            read();
1448:
1449:                            return new Expression(type, a, readConcat());
1450:                        }
1451:
1452:                        return a;
1453:                    }
1454:                    }
1455:
1456:                    if (not) {
1457:                        a = new Expression(Expression.NOT, a, null);
1458:                    }
1459:
1460:                    return a;
1461:                }
1462:                }
1463:            }
1464:
1465:            private Expression parseLikePredicate(Expression a)
1466:                    throws HsqlException {
1467:
1468:                read();
1469:
1470:                Expression b = readConcat();
1471:                Character escape = null;
1472:
1473:                if (sToken.equals(Token.T_ESCAPE)) {
1474:                    read();
1475:
1476:                    Expression c = readTerm();
1477:
1478:                    Trace.check(c.getType() == Expression.VALUE,
1479:                            Trace.INVALID_ESCAPE);
1480:
1481:                    String s = (String) c.getValue(session, Types.VARCHAR);
1482:
1483:                    // boucherb@users 2003-09-25
1484:                    // CHECKME:
1485:                    // Assert s.length() == 1 for xxxchar comparisons?
1486:                    // TODO:
1487:                    // SQL200n says binary escape can be 1 or more octets.
1488:                    // Maybe we need to retain s and check this in
1489:                    // Expression.resolve()?
1490:                    if (s == null || s.length() < 1) {
1491:                        throw Trace.error(Trace.INVALID_ESCAPE, s);
1492:                    }
1493:
1494:                    escape = new Character(s.charAt(0));
1495:                }
1496:
1497:                boolean hasCollation = database.collation.name != null;
1498:
1499:                a = new Expression(a, b, escape, hasCollation);
1500:
1501:                return a;
1502:            }
1503:
1504:            private Expression parseBetweenPredicate(Expression a)
1505:                    throws HsqlException {
1506:
1507:                read();
1508:
1509:                Expression l = new Expression(Expression.BIGGER_EQUAL, a,
1510:                        readConcat());
1511:
1512:                readThis(Expression.AND);
1513:
1514:                Expression h = new Expression(Expression.SMALLER_EQUAL, a,
1515:                        readConcat());
1516:
1517:                if (l.getArg().isParam() && l.getArg2().isParam()) {
1518:                    throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
1519:                            Trace.Parser_ambiguous_between1);
1520:                }
1521:
1522:                if (h.getArg().isParam() && h.getArg2().isParam()) {
1523:                    throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
1524:                            Trace.Parser_ambiguous_between1);
1525:                }
1526:
1527:                return new Expression(Expression.AND, l, h);
1528:            }
1529:
1530:            private Expression parseInPredicate(Expression a)
1531:                    throws HsqlException {
1532:
1533:                int type = iToken;
1534:
1535:                read();
1536:                readThis(Expression.OPEN);
1537:
1538:                Expression b = null;
1539:                int brackets = 0;
1540:
1541:                if (iToken == Expression.OPEN) {
1542:                    brackets += parseOpenBrackets() + 1;
1543:
1544:                    read();
1545:                }
1546:
1547:                if (iToken == Expression.SELECT) {
1548:                    SubQuery sq = parseSubquery(brackets, null, false,
1549:                            Expression.IN);
1550:
1551:                    // until we support rows in IN predicates
1552:                    Trace.check(sq.select.iResultLen == 1,
1553:                            Trace.SINGLE_COLUMN_EXPECTED);
1554:
1555:                    b = new Expression(sq);
1556:
1557:                    read();
1558:                } else {
1559:                    tokenizer.back();
1560:
1561:                    HsqlArrayList v = new HsqlArrayList();
1562:
1563:                    while (true) {
1564:                        Expression value = parseExpression();
1565:
1566:                        if (value.exprType == Expression.VALUE
1567:                                && value.valueData == null && !value.isParam()) {
1568:                            throw Trace.error(Trace.NULL_IN_VALUE_LIST);
1569:                        }
1570:
1571:                        v.add(value);
1572:                        read();
1573:
1574:                        if (iToken != Expression.COMMA) {
1575:                            break;
1576:                        }
1577:                    }
1578:
1579:                    Expression[] valueList;
1580:
1581:                    valueList = (Expression[]) v.toArray(new Expression[v
1582:                            .size()]);
1583:                    b = new Expression(valueList);
1584:                }
1585:
1586:                readThis(Expression.CLOSE);
1587:
1588:                return new Expression(type, a, b);
1589:            }
1590:
1591:            private Expression parseAllAnyPredicate() throws HsqlException {
1592:
1593:                int type = iToken;
1594:
1595:                read();
1596:                readThis(Expression.OPEN);
1597:
1598:                Expression b = null;
1599:                int brackets = 0;
1600:
1601:                if (iToken == Expression.OPEN) {
1602:                    brackets += parseOpenBrackets() + 1;
1603:
1604:                    read();
1605:                }
1606:
1607:                if (iToken != Expression.SELECT) {
1608:                    throw Trace.error(Trace.INVALID_IDENTIFIER);
1609:                }
1610:
1611:                SubQuery sq = parseSubquery(brackets, null, false, type);
1612:                Select select = sq.select;
1613:
1614:                // until we support rows
1615:                Trace.check(sq.select.iResultLen == 1,
1616:                        Trace.SINGLE_COLUMN_EXPECTED);
1617:
1618:                b = new Expression(sq);
1619:
1620:                read();
1621:                readThis(Expression.CLOSE);
1622:
1623:                return new Expression(type, b, null);
1624:            }
1625:
1626:            /**
1627:             *  Method declaration
1628:             *
1629:             * @param  type
1630:             * @throws  HsqlException
1631:             */
1632:            private void readThis(int type) throws HsqlException {
1633:                Trace.check(iToken == type, Trace.UNEXPECTED_TOKEN);
1634:                read();
1635:            }
1636:
1637:            /**
1638:             *  Method declaration
1639:             *
1640:             * @return a concatenation, possibly degenerate
1641:             * @throws  HsqlException
1642:             */
1643:            private Expression readConcat() throws HsqlException {
1644:
1645:                Expression r = readSum();
1646:
1647:                while (iToken == Expression.CONCAT) {
1648:                    int type = Expression.CONCAT;
1649:                    Expression a = r;
1650:
1651:                    read();
1652:
1653:                    r = new Expression(type, a, readSum());
1654:                }
1655:
1656:                return r;
1657:            }
1658:
1659:            static HashMap simpleFunctions = new HashMap();
1660:
1661:            static {
1662:                simpleFunctions.put(Token.T_CURRENT_DATE,
1663:                        "org.hsqldb.Library.curdate");
1664:                simpleFunctions.put(Token.T_CURRENT_TIME,
1665:                        "org.hsqldb.Library.curtime");
1666:                simpleFunctions.put(Token.T_CURRENT_TIMESTAMP,
1667:                        "org.hsqldb.Library.now");
1668:                simpleFunctions.put(Token.T_CURRENT_USER,
1669:                        "org.hsqldb.Library.user");
1670:                simpleFunctions.put(Token.T_SYSDATE,
1671:                        "org.hsqldb.Library.curdate");
1672:                simpleFunctions.put(Token.T_NOW, "org.hsqldb.Library.now");
1673:                simpleFunctions
1674:                        .put(Token.T_TODAY, "org.hsqldb.Library.curdate");
1675:            }
1676:
1677:            /**
1678:             *  Method declaration
1679:             *
1680:             * @return  a summation, possibly degenerate
1681:             * @throws  HsqlException
1682:             */
1683:            private Expression readSum() throws HsqlException {
1684:
1685:                Expression r = readFactor();
1686:
1687:                while (true) {
1688:                    int type;
1689:
1690:                    if (iToken == Expression.PLUS) {
1691:                        type = Expression.ADD;
1692:                    } else if (iToken == Expression.NEGATE) {
1693:                        type = Expression.SUBTRACT;
1694:                    } else {
1695:                        break;
1696:                    }
1697:
1698:                    Expression a = r;
1699:
1700:                    read();
1701:
1702:                    r = new Expression(type, a, readFactor());
1703:                }
1704:
1705:                return r;
1706:            }
1707:
1708:            /**
1709:             *  Method declaration
1710:             *
1711:             * @return  a product, possibly degenerate
1712:             * @throws  HsqlException
1713:             */
1714:            private Expression readFactor() throws HsqlException {
1715:
1716:                Expression r = readTerm();
1717:
1718:                while (iToken == Expression.MULTIPLY
1719:                        || iToken == Expression.DIVIDE) {
1720:                    int type = iToken;
1721:                    Expression a = r;
1722:
1723:                    read();
1724:
1725:                    r = new Expression(type, a, readTerm());
1726:                }
1727:
1728:                return r;
1729:            }
1730:
1731:            /**
1732:             *  Method declaration
1733:             *
1734:             * @return  a term, possibly composite
1735:             * @throws  HsqlException
1736:             */
1737:            private Expression readTerm() throws HsqlException {
1738:
1739:                Expression r = null;
1740:
1741:                switch (iToken) {
1742:
1743:                case Expression.COLUMN: {
1744:                    r = readColumnExpression();
1745:
1746:                    break;
1747:                }
1748:                case Expression.NEGATE: {
1749:                    int type = iToken;
1750:
1751:                    read();
1752:
1753:                    r = new Expression(type, readTerm(), null);
1754:
1755:                    Trace.check(!r.getArg().isParam(),
1756:                            Trace.Expression_resolveTypes1);
1757:
1758:                    break;
1759:                }
1760:                case Expression.PLUS: {
1761:                    read();
1762:
1763:                    r = readTerm();
1764:
1765:                    Trace.check(!r.isParam(), Trace.UNRESOLVED_PARAMETER_TYPE,
1766:                            Trace.getMessage(Trace.Expression_resolveTypes1));
1767:
1768:                    break;
1769:                }
1770:                case Expression.OPEN: {
1771:                    read();
1772:
1773:                    r = readOr();
1774:
1775:                    if (iToken != Expression.CLOSE) {
1776:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1777:                    }
1778:
1779:                    read();
1780:
1781:                    break;
1782:                }
1783:                case Expression.VALUE: {
1784:                    r = new Expression(iType, oData);
1785:
1786:                    read();
1787:
1788:                    break;
1789:                }
1790:                case Expression.PARAM: {
1791:                    r = new Expression(Types.NULL, null, true);
1792:
1793:                    parameters.add(r);
1794:                    read();
1795:
1796:                    break;
1797:                }
1798:                case Expression.SELECT: {
1799:                    SubQuery sq = parseSubquery(0, null, false,
1800:                            Expression.SELECT);
1801:
1802:                    r = new Expression(sq);
1803:
1804:                    read();
1805:
1806:                    break;
1807:                }
1808:                case Expression.ANY:
1809:                case Expression.ALL: {
1810:                    r = parseAllAnyPredicate();
1811:
1812:                    //                read();
1813:                    break;
1814:                }
1815:                case Expression.MULTIPLY: {
1816:                    r = new Expression(sSchema, sTable, (String) null);
1817:
1818:                    read();
1819:
1820:                    break;
1821:                }
1822:                case Expression.CASEWHEN:
1823:                    return readCaseWhenExpression();
1824:
1825:                case Expression.CASE:
1826:                    return readCaseExpression();
1827:
1828:                case Expression.NULLIF:
1829:                    return readNullIfExpression();
1830:
1831:                case Expression.COALESCE:
1832:                case Expression.IFNULL:
1833:                    return readCoalesceExpression();
1834:
1835:                case Expression.SEQUENCE:
1836:                    return readSequenceExpression();
1837:
1838:                case Expression.CAST:
1839:                case Expression.CONVERT:
1840:                    return readCastExpression();
1841:
1842:                case Expression.EXTRACT:
1843:                    return readExtractExpression();
1844:
1845:                case Expression.TRIM:
1846:                    return readTrimExpression();
1847:
1848:                case Expression.POSITION:
1849:                    return readPositionExpression();
1850:
1851:                case Expression.SUBSTRING:
1852:                    return readSubstringExpression();
1853:
1854:                default:
1855:                    if (Expression.isAggregate(iToken)) {
1856:                        return readAggregate();
1857:                    } else {
1858:                        throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1859:                    }
1860:                }
1861:
1862:                return r;
1863:            }
1864:
1865:            /**
1866:             * reads a CASE .. WHEN expression
1867:             */
1868:            Expression readCaseExpression() throws HsqlException {
1869:
1870:                int type = Expression.CASEWHEN;
1871:                Expression r = null;
1872:                Expression predicand = null;
1873:
1874:                read();
1875:
1876:                if (iToken != Expression.WHEN) {
1877:                    predicand = readOr();
1878:                }
1879:
1880:                Expression leaf = null;
1881:
1882:                while (true) {
1883:                    Expression casewhen = parseCaseWhen(predicand);
1884:
1885:                    if (r == null) {
1886:                        r = casewhen;
1887:                    } else {
1888:                        leaf.setRightExpression(casewhen);
1889:                    }
1890:
1891:                    leaf = casewhen.getRightExpression();
1892:
1893:                    if (iToken != Expression.WHEN) {
1894:                        break;
1895:                    }
1896:                }
1897:
1898:                if (iToken == Expression.ELSE) {
1899:                    readThis(Expression.ELSE);
1900:
1901:                    Expression elsexpr = readOr();
1902:
1903:                    leaf.setRightExpression(elsexpr);
1904:                }
1905:
1906:                readThis(Expression.ENDWHEN);
1907:
1908:                return r;
1909:            }
1910:
1911:            /**
1912:             * Reads part of a CASE .. WHEN  expression
1913:             */
1914:            private Expression parseCaseWhen(Expression r) throws HsqlException {
1915:
1916:                readThis(Expression.WHEN);
1917:
1918:                Expression condition;
1919:
1920:                if (r == null) {
1921:                    condition = readOr();
1922:                } else {
1923:                    condition = new Expression(Expression.EQUAL, r, readOr());
1924:                }
1925:
1926:                readThis(Expression.THEN);
1927:
1928:                Expression current = readOr();
1929:                Expression alternatives = new Expression(
1930:                        Expression.ALTERNATIVE, current, new Expression(
1931:                                Types.NULL, null));
1932:                Expression casewhen = new Expression(Expression.CASEWHEN,
1933:                        condition, alternatives);
1934:
1935:                return casewhen;
1936:            }
1937:
1938:            /**
1939:             * reads a CASEWHEN expression
1940:             */
1941:            private Expression readCaseWhenExpression() throws HsqlException {
1942:
1943:                int type = iToken;
1944:                Expression r = null;
1945:
1946:                read();
1947:                readThis(Expression.OPEN);
1948:
1949:                r = readOr();
1950:
1951:                readThis(Expression.COMMA);
1952:
1953:                Expression thenelse = readOr();
1954:
1955:                readThis(Expression.COMMA);
1956:
1957:                // thenelse part is never evaluated; only init
1958:                thenelse = new Expression(Expression.ALTERNATIVE, thenelse,
1959:                        readOr());
1960:                r = new Expression(type, r, thenelse);
1961:
1962:                readThis(Expression.CLOSE);
1963:
1964:                return r;
1965:            }
1966:
1967:            /**
1968:             * Reads a CAST or CONVERT expression
1969:             */
1970:            private Expression readCastExpression() throws HsqlException {
1971:
1972:                boolean isConvert = iToken == Expression.CONVERT;
1973:
1974:                read();
1975:                readThis(Expression.OPEN);
1976:
1977:                Expression r = readOr();
1978:
1979:                if (isConvert) {
1980:                    readThis(Expression.COMMA);
1981:                } else {
1982:                    readThis(Expression.AS);
1983:                }
1984:
1985:                int typeNr = Types.getTypeNr(sToken);
1986:                int length = 0;
1987:                int scale = 0;
1988:                boolean hasLength = false;
1989:
1990:                if (Types.acceptsPrecisionCreateParam(typeNr)
1991:                        && tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1992:                    length = tokenizer.getInt();
1993:                    hasLength = true;
1994:
1995:                    if (Types.acceptsScaleCreateParam(typeNr)
1996:                            && tokenizer.isGetThis(Token.T_COMMA)) {
1997:                        scale = tokenizer.getInt();
1998:                    }
1999:
2000:                    tokenizer.getThis(Token.T_CLOSEBRACKET);
2001:                }
2002:
2003:                if (typeNr == Types.FLOAT && length > 53) {
2004:                    throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
2005:                }
2006:
2007:                if (typeNr == Types.TIMESTAMP) {
2008:                    if (!hasLength) {
2009:                        length = 6;
2010:                    } else if (length != 0 && length != 6) {
2011:                        throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
2012:                    }
2013:                }
2014:
2015:                if (r.isParam()) {
2016:                    r.setDataType(typeNr);
2017:                }
2018:
2019:                r = new Expression(r, typeNr, length, scale);
2020:
2021:                read();
2022:                readThis(Expression.CLOSE);
2023:
2024:                return r;
2025:            }
2026:
2027:            /**
2028:             * reads a Column or Function expression
2029:             */
2030:            private Expression readColumnExpression() throws HsqlException {
2031:
2032:                String name = sToken;
2033:                Expression r = new Expression(sTable, name, wasQuoted);
2034:
2035:                read();
2036:
2037:                if (iToken == Expression.OPEN) {
2038:                    String javaName = database.getJavaName(name);
2039:                    Function f = new Function(name, javaName, false);
2040:
2041:                    session.check(javaName);
2042:
2043:                    int len = f.getArgCount();
2044:                    int i = 0;
2045:
2046:                    read();
2047:
2048:                    if (iToken != Expression.CLOSE) {
2049:                        while (true) {
2050:                            f.setArgument(i++, readOr());
2051:
2052:                            if (iToken != Expression.COMMA) {
2053:                                break;
2054:                            }
2055:
2056:                            read();
2057:                        }
2058:                    }
2059:
2060:                    readThis(Expression.CLOSE);
2061:
2062:                    r = new Expression(f);
2063:                } else {
2064:                    String javaName = (String) simpleFunctions.get(name);
2065:
2066:                    if (javaName != null) {
2067:                        Function f = new Function(name, javaName, true);
2068:
2069:                        r = new Expression(f);
2070:                    }
2071:                }
2072:
2073:                return r;
2074:            }
2075:
2076:            /**
2077:             * reads a CONCAT expression
2078:             */
2079:            private Expression readConcatExpression() throws HsqlException {
2080:
2081:                int type = iToken;
2082:
2083:                read();
2084:                readThis(Expression.OPEN);
2085:
2086:                Expression r = readOr();
2087:
2088:                readThis(Expression.COMMA);
2089:
2090:                r = new Expression(type, r, readOr());
2091:
2092:                readThis(Expression.CLOSE);
2093:
2094:                return r;
2095:            }
2096:
2097:            /**
2098:             * Reads a NULLIF expression
2099:             */
2100:            private Expression readNullIfExpression() throws HsqlException {
2101:
2102:                // turn into a CASEWHEN
2103:                read();
2104:                readThis(Expression.OPEN);
2105:
2106:                Expression r = readOr();
2107:
2108:                readThis(Expression.COMMA);
2109:
2110:                Expression thenelse = new Expression(Expression.ALTERNATIVE,
2111:                        new Expression(Types.NULL, null), r);
2112:
2113:                r = new Expression(Expression.EQUAL, r, readOr());
2114:                r = new Expression(Expression.CASEWHEN, r, thenelse);
2115:
2116:                readThis(Expression.CLOSE);
2117:
2118:                return r;
2119:            }
2120:
2121:            /**
2122:             * Reads a COALESE or IFNULL expression
2123:             */
2124:            private Expression readCoalesceExpression() throws HsqlException {
2125:
2126:                Expression r = null;
2127:
2128:                // turn into a CASEWHEN
2129:                read();
2130:                readThis(Expression.OPEN);
2131:
2132:                Expression leaf = null;
2133:
2134:                while (true) {
2135:                    Expression current = readOr();
2136:
2137:                    if (leaf != null && iToken == Expression.CLOSE) {
2138:                        readThis(Expression.CLOSE);
2139:                        leaf.setLeftExpression(current);
2140:
2141:                        break;
2142:                    }
2143:
2144:                    Expression condition = new Expression(Expression.IS_NULL,
2145:                            current, null);
2146:                    Expression alternatives = new Expression(
2147:                            Expression.ALTERNATIVE, new Expression(Types.NULL,
2148:                                    null), current);
2149:                    Expression casewhen = new Expression(Expression.CASEWHEN,
2150:                            condition, alternatives);
2151:
2152:                    if (r == null) {
2153:                        r = casewhen;
2154:                    } else {
2155:                        leaf.setLeftExpression(casewhen);
2156:                    }
2157:
2158:                    leaf = alternatives;
2159:
2160:                    readThis(Expression.COMMA);
2161:                }
2162:
2163:                return r;
2164:            }
2165:
2166:            /**
2167:             * Reads an EXTRACT expression
2168:             */
2169:            private Expression readExtractExpression() throws HsqlException {
2170:
2171:                read();
2172:                readThis(Expression.OPEN);
2173:
2174:                String name = sToken;
2175:
2176:                // must be an accepted identifier
2177:                if (!Expression.SQL_EXTRACT_FIELD_NAMES.contains(name)) {
2178:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2179:                }
2180:
2181:                readToken();
2182:                readThis(Expression.FROM);
2183:
2184:                // the name argument is DAY, MONTH etc.  - OK for now for CHECK constraints
2185:                Function f = new Function(name, database.getJavaName(name),
2186:                        false);
2187:
2188:                f.setArgument(0, readOr());
2189:                readThis(Expression.CLOSE);
2190:
2191:                return new Expression(f);
2192:            }
2193:
2194:            /**
2195:             * Reads a POSITION expression
2196:             */
2197:            private Expression readPositionExpression() throws HsqlException {
2198:
2199:                read();
2200:                readThis(Expression.OPEN);
2201:
2202:                Function f = new Function(Token.T_POSITION,
2203:                        "org.hsqldb.Library.position", false);
2204:
2205:                f.setArgument(0, readTerm());
2206:                readThis(Expression.IN);
2207:                f.setArgument(1, readOr());
2208:                readThis(Expression.CLOSE);
2209:
2210:                return new Expression(f);
2211:            }
2212:
2213:            /**
2214:             * Reads a SUBSTRING expression
2215:             */
2216:            private Expression readSubstringExpression() throws HsqlException {
2217:
2218:                boolean commas = false;
2219:
2220:                read();
2221:                readThis(Expression.OPEN);
2222:
2223:                // OK for now for CHECK search conditions
2224:                Function f = new Function(Token.T_SUBSTRING,
2225:                        "org.hsqldb.Library.substring", false);
2226:
2227:                f.setArgument(0, readTerm());
2228:
2229:                if (iToken == Expression.FROM) {
2230:                    readThis(Expression.FROM);
2231:                } else {
2232:                    readThis(Expression.COMMA);
2233:
2234:                    commas = true;
2235:                }
2236:
2237:                f.setArgument(1, readOr());
2238:
2239:                Expression count = null;
2240:
2241:                if (!commas && iToken == Expression.FOR) {
2242:                    readThis(Expression.FOR);
2243:
2244:                    count = readTerm();
2245:                } else if (commas && iToken == Expression.COMMA) {
2246:                    readThis(Expression.COMMA);
2247:
2248:                    count = readTerm();
2249:                }
2250:
2251:                f.setArgument(2, count);
2252:                readThis(Expression.CLOSE);
2253:
2254:                return new Expression(f);
2255:            }
2256:
2257:            private Expression readSequenceExpression() throws HsqlException {
2258:
2259:                tokenizer.getThis(Token.T_VALUE);
2260:                tokenizer.getThis(Token.T_FOR);
2261:
2262:                String name = tokenizer.getName();
2263:                String schemaname = tokenizer.getLongNameFirst();
2264:
2265:                schemaname = session.getSchemaName(schemaname);
2266:
2267:                // Read next because Tokenizer.back() will run after this.
2268:                // (This is because usually when reading expressions, you need to
2269:                // get the following token to know whether you have finished.
2270:                tokenizer.getString();
2271:
2272:                NumberSequence sequence = database.schemaManager.getSequence(
2273:                        name, schemaname);
2274:
2275:                return new Expression(sequence);
2276:            }
2277:
2278:            /**
2279:             * Reads a TRIM expression
2280:             */
2281:            private Expression readTrimExpression() throws HsqlException {
2282:
2283:                read();
2284:                readThis(Expression.OPEN);
2285:
2286:                String type = sToken;
2287:
2288:                if (Expression.SQL_TRIM_SPECIFICATION.contains(type)) {
2289:                    read();
2290:                } else {
2291:                    type = Token.T_BOTH;
2292:                }
2293:
2294:                String trimstr;
2295:
2296:                if (sToken.length() == 1) {
2297:                    trimstr = sToken;
2298:
2299:                    read();
2300:                } else {
2301:                    trimstr = " ";
2302:                }
2303:
2304:                readThis(Expression.FROM);
2305:
2306:                Expression trim = new Expression(Types.CHAR, trimstr);
2307:                Expression leading;
2308:                Expression trailing;
2309:
2310:                if (type.equals(Token.T_LEADING)) {
2311:                    leading = new Expression(true);
2312:                    trailing = new Expression(false);
2313:                } else if (type.equals(Token.T_TRAILING)) {
2314:                    leading = new Expression(false);
2315:                    trailing = new Expression(true);
2316:                } else {
2317:                    leading = trailing = new Expression(true);
2318:                }
2319:
2320:                // name argument is OK for now for CHECK constraints
2321:                Function f = new Function(Token.T_TRIM,
2322:                        "org.hsqldb.Library.trim", false);
2323:
2324:                f.setArgument(0, readOr());
2325:                f.setArgument(1, trim);
2326:                f.setArgument(2, leading);
2327:                f.setArgument(3, trailing);
2328:                readThis(Expression.CLOSE);
2329:
2330:                return new Expression(f);
2331:            }
2332:
2333:            /**
2334:             *  Reads a DEFAULT clause expression.
2335:             */
2336:            Expression readDefaultClause(int dataType) throws HsqlException {
2337:
2338:                Expression r = null;
2339:
2340:                read();
2341:
2342:                switch (iToken) {
2343:
2344:                case Expression.COLUMN: {
2345:                    String name = sToken;
2346:                    String javaName = (String) simpleFunctions.get(name);
2347:
2348:                    if (javaName != null) {
2349:                        Function f = new Function(name, javaName, true);
2350:
2351:                        return new Expression(f);
2352:                    }
2353:
2354:                    break;
2355:                }
2356:                case Expression.NEGATE: {
2357:                    int exprType = iToken;
2358:
2359:                    read();
2360:
2361:                    if (iToken == Expression.VALUE) {
2362:                        oData = Column.convertObject(oData, dataType);
2363:
2364:                        return new Expression(exprType, new Expression(
2365:                                dataType, oData), null);
2366:                    }
2367:
2368:                    break;
2369:                }
2370:                case Expression.VALUE: {
2371:                    String name = sToken.toUpperCase(Locale.ENGLISH);
2372:                    String javaName = (String) simpleFunctions.get(name);
2373:
2374:                    if (Types.isDatetimeType(dataType) && javaName != null) {
2375:                        Function f = new Function(name, javaName, true);
2376:
2377:                        return new Expression(f);
2378:                    }
2379:
2380:                    oData = Column.convertObject(oData, dataType);
2381:
2382:                    return new Expression(dataType, oData);
2383:                }
2384:                }
2385:
2386:                throw Trace.error(Trace.WRONG_DEFAULT_CLAUSE, sToken);
2387:            }
2388:
2389:            /**
2390:             *  Method declaration
2391:             *
2392:             * @throws  HsqlException
2393:             */
2394:            private void read() throws HsqlException {
2395:
2396:                sToken = tokenizer.getString();
2397:                wasQuoted = tokenizer.wasQuotedIdentifier();
2398:
2399:                if (tokenizer.wasValue()) {
2400:                    iToken = Expression.VALUE;
2401:                    oData = tokenizer.getAsValue();
2402:                    iType = tokenizer.getType();
2403:                } else if (tokenizer.wasSimpleName()) {
2404:                    iToken = Expression.COLUMN;
2405:                    sTable = null;
2406:                } else if (tokenizer.wasLongName()) {
2407:                    sSchema = tokenizer.getLongNamePre();
2408:                    sTable = tokenizer.getLongNameFirst();
2409:
2410:                    if (sToken.equals(Token.T_MULTIPLY)) {
2411:                        iToken = Expression.MULTIPLY;
2412:                    } else {
2413:                        iToken = Expression.COLUMN;
2414:                    }
2415:                } else if (tokenizer.wasParameter()) {
2416:                    iToken = Expression.PARAM;
2417:                } else if (sToken.length() == 0) {
2418:                    iToken = Expression.END;
2419:                } else {
2420:                    iToken = tokenSet.get(sToken, -1);
2421:
2422:                    if (iToken == -1) {
2423:                        iToken = Expression.END;
2424:                    }
2425:
2426:                    switch (iToken) {
2427:
2428:                    case Expression.COMMA:
2429:                    case Expression.EQUAL:
2430:                    case Expression.NOT_EQUAL:
2431:                    case Expression.SMALLER:
2432:                    case Expression.BIGGER:
2433:                    case Expression.SMALLER_EQUAL:
2434:                    case Expression.BIGGER_EQUAL:
2435:                    case Expression.AND:
2436:                    case Expression.OR:
2437:                    case Expression.NOT:
2438:                    case Expression.ALL:
2439:                    case Expression.ANY:
2440:                    case Expression.IN:
2441:                    case Expression.EXISTS:
2442:                    case Expression.BETWEEN:
2443:                    case Expression.PLUS:
2444:                    case Expression.NEGATE:
2445:                    case Expression.DIVIDE:
2446:                    case Expression.CONCAT:
2447:                    case Expression.OPEN:
2448:                    case Expression.CLOSE:
2449:                    case Expression.SELECT:
2450:                    case Expression.LIKE:
2451:                    case Expression.COUNT:
2452:                    case Expression.SUM:
2453:                    case Expression.MIN:
2454:                    case Expression.MAX:
2455:                    case Expression.AVG:
2456:                    case Expression.EVERY:
2457:                    case Expression.SOME:
2458:                    case Expression.STDDEV_POP:
2459:                    case Expression.STDDEV_SAMP:
2460:                    case Expression.VAR_POP:
2461:                    case Expression.VAR_SAMP:
2462:                    case Expression.CONVERT:
2463:                    case Expression.CAST:
2464:                    case Expression.SEQUENCE:
2465:                    case Expression.IFNULL:
2466:                    case Expression.COALESCE:
2467:                    case Expression.NULLIF:
2468:                    case Expression.CASE:
2469:                    case Expression.WHEN:
2470:                    case Expression.THEN:
2471:                    case Expression.ELSE:
2472:                    case Expression.ENDWHEN:
2473:                    case Expression.CASEWHEN:
2474:                    case Expression.EXTRACT:
2475:                    case Expression.POSITION:
2476:                    case Expression.SUBSTRING:
2477:                    case Expression.FROM:
2478:                    case Expression.FOR:
2479:                    case Expression.END:
2480:                    case Expression.PARAM:
2481:                    case Expression.TRIM:
2482:                    case Expression.LEADING:
2483:                    case Expression.TRAILING:
2484:                    case Expression.BOTH:
2485:                    case Expression.AS:
2486:                    case Expression.IS:
2487:                    case Expression.DISTINCT:
2488:                        break; // nothing else required, iToken initialized properly
2489:
2490:                    case Expression.MULTIPLY:
2491:                        sTable = null; // in case of ASTERIX
2492:                        break;
2493:
2494:                    default:
2495:                        iToken = Expression.END;
2496:                    }
2497:                }
2498:            }
2499:
2500:            /**
2501:             * A workaround for parsing EXTRACT clause elements such as MONTH, DAY
2502:             * and YEAR, without having to make each of them SQL KEYWORDS in Tokenizer.
2503:             *
2504:             * @throws HsqlException if a tokenization error occurs
2505:             */
2506:            private void readToken() throws HsqlException {
2507:                sToken = tokenizer.getString();
2508:                iToken = tokenSet.get(sToken, -1);
2509:            }
2510:
2511:            private static IntValueHashMap tokenSet = new IntValueHashMap(37);
2512:
2513:            static {
2514:                tokenSet.put(Token.T_COMMA, Expression.COMMA);
2515:                tokenSet.put(Token.T_EQUALS, Expression.EQUAL);
2516:                tokenSet.put("!=", Expression.NOT_EQUAL);
2517:                tokenSet.put("<>", Expression.NOT_EQUAL);
2518:                tokenSet.put("<", Expression.SMALLER);
2519:                tokenSet.put(">", Expression.BIGGER);
2520:                tokenSet.put("<=", Expression.SMALLER_EQUAL);
2521:                tokenSet.put(">=", Expression.BIGGER_EQUAL);
2522:                tokenSet.put(Token.T_AND, Expression.AND);
2523:                tokenSet.put(Token.T_NOT, Expression.NOT);
2524:                tokenSet.put(Token.T_OR, Expression.OR);
2525:                tokenSet.put(Token.T_ALL, Expression.ALL);
2526:                tokenSet.put(Token.T_ANY, Expression.ANY);
2527:                tokenSet.put(Token.T_IN, Expression.IN);
2528:                tokenSet.put(Token.T_EXISTS, Expression.EXISTS);
2529:                tokenSet.put(Token.T_BETWEEN, Expression.BETWEEN);
2530:                tokenSet.put(Token.T_PLUS, Expression.PLUS);
2531:                tokenSet.put("-", Expression.NEGATE);
2532:                tokenSet.put(Token.T_MULTIPLY, Expression.MULTIPLY);
2533:                tokenSet.put("/", Expression.DIVIDE);
2534:                tokenSet.put("||", Expression.CONCAT);
2535:                tokenSet.put(Token.T_OPENBRACKET, Expression.OPEN);
2536:                tokenSet.put(Token.T_CLOSEBRACKET, Expression.CLOSE);
2537:                tokenSet.put(Token.T_SELECT, Expression.SELECT);
2538:                tokenSet.put(Token.T_LIKE, Expression.LIKE);
2539:                tokenSet.put(Token.T_COUNT, Expression.COUNT);
2540:                tokenSet.put(Token.T_SUM, Expression.SUM);
2541:                tokenSet.put(Token.T_MIN, Expression.MIN);
2542:                tokenSet.put(Token.T_MAX, Expression.MAX);
2543:                tokenSet.put(Token.T_AVG, Expression.AVG);
2544:                tokenSet.put(Token.T_EVERY, Expression.EVERY);
2545:                tokenSet.put(Token.T_SOME, Expression.SOME);
2546:                tokenSet.put(Token.T_STDDEV_POP, Expression.STDDEV_POP);
2547:                tokenSet.put(Token.T_STDDEV_SAMP, Expression.STDDEV_SAMP);
2548:                tokenSet.put(Token.T_VAR_POP, Expression.VAR_POP);
2549:                tokenSet.put(Token.T_VAR_SAMP, Expression.VAR_SAMP);
2550:                tokenSet.put(Token.T_IFNULL, Expression.IFNULL);
2551:                tokenSet.put(Token.T_NVL, Expression.IFNULL);
2552:                tokenSet.put(Token.T_NULLIF, Expression.NULLIF);
2553:                tokenSet.put(Token.T_CONVERT, Expression.CONVERT);
2554:                tokenSet.put(Token.T_CAST, Expression.CAST);
2555:                tokenSet.put(Token.T_NEXT, Expression.SEQUENCE);
2556:                tokenSet.put(Token.T_CASE, Expression.CASE);
2557:                tokenSet.put(Token.T_WHEN, Expression.WHEN);
2558:                tokenSet.put(Token.T_THEN, Expression.THEN);
2559:                tokenSet.put(Token.T_ELSE, Expression.ELSE);
2560:                tokenSet.put(Token.T_END, Expression.ENDWHEN);
2561:                tokenSet.put(Token.T_CASEWHEN, Expression.CASEWHEN);
2562:                tokenSet.put(Token.T_COALESCE, Expression.COALESCE);
2563:                tokenSet.put(Token.T_EXTRACT, Expression.EXTRACT);
2564:                tokenSet.put(Token.T_POSITION, Expression.POSITION);
2565:                tokenSet.put(Token.T_FROM, Expression.FROM);
2566:                tokenSet.put(Token.T_TRIM, Expression.TRIM);
2567:                tokenSet.put(Token.T_SUBSTRING, Expression.SUBSTRING);
2568:                tokenSet.put(Token.T_FOR, Expression.FOR);
2569:                tokenSet.put(Token.T_AS, Expression.AS);
2570:                tokenSet.put(Token.T_IS, Expression.IS);
2571:                tokenSet.put(Token.T_QUESTION, Expression.PARAM);
2572:            }
2573:
2574:            // boucherb@users 20030411 - patch 1.7.2 - for prepared statements
2575:            // ---------------------------------------------------------------
2576:            HsqlArrayList parameters = new HsqlArrayList();
2577:            private static final Expression[] noParameters = new Expression[0];
2578:            private static final SubQuery[] noSubqueries = new SubQuery[0];
2579:
2580:            /**
2581:             *  Destructive get method
2582:             */
2583:            Expression[] getParameters() {
2584:
2585:                Expression[] result = parameters.size() == 0 ? noParameters
2586:                        : (Expression[]) parameters
2587:                                .toArray(new Expression[parameters.size()]);
2588:
2589:                parameters.clear();
2590:
2591:                return result;
2592:            }
2593:
2594:            void clearParameters() {
2595:                parameters.clear();
2596:            }
2597:
2598:            // fredt - new implementation of subquery list
2599:
2600:            /**
2601:             * Sets the subqueries as belonging to the View being constructed
2602:             */
2603:            void setAsView(View view) {
2604:
2605:                for (int i = 0; i < subQueryList.size(); i++) {
2606:                    SubQuery sq = (SubQuery) subQueryList.get(i);
2607:
2608:                    if (sq.view == null) {
2609:                        sq.view = view;
2610:                    }
2611:                }
2612:            }
2613:
2614:            /**
2615:             * Return the list of subqueries as an array sorted according to the order
2616:             * of materialization, then clear the internal subquery list
2617:             */
2618:            SubQuery[] getSortedSubqueries() {
2619:
2620:                if (subQueryList.size() == 0) {
2621:                    return noSubqueries;
2622:                }
2623:
2624:                subQueryList.sort((SubQuery) subQueryList.get(0));
2625:
2626:                SubQuery[] subqueries = new SubQuery[subQueryList.size()];
2627:
2628:                subQueryList.toArray(subqueries);
2629:                subQueryList.clear();
2630:
2631:                return subqueries;
2632:            }
2633:
2634:            /**
2635:             * Retrieves a CALL-type CompiledStatement from this parse context.
2636:             */
2637:            CompiledStatement compileCallStatement() throws HsqlException {
2638:
2639:                clearParameters();
2640:
2641:                Expression expression = parseExpression();
2642:                CompiledStatement cs = new CompiledStatement(session, database,
2643:                        session.currentSchema, expression,
2644:                        getSortedSubqueries(), getParameters());
2645:
2646:                return cs;
2647:            }
2648:
2649:            /**
2650:             * Retrieves a DELETE-type CompiledStatement from this parse context.
2651:             */
2652:            CompiledStatement compileDeleteStatement() throws HsqlException {
2653:
2654:                String token;
2655:                Expression condition = null;
2656:                TableFilter tableFilter;
2657:
2658:                clearParameters();
2659:                tokenizer.getThis(Token.T_FROM);
2660:
2661:                tableFilter = parseSimpleTableFilter(UserManager.DELETE);
2662:                token = tokenizer.getString();
2663:
2664:                if (token.equals(Token.T_WHERE)) {
2665:                    condition = parseExpression();
2666:                } else {
2667:                    tokenizer.back();
2668:                }
2669:
2670:                CompiledStatement cs = new CompiledStatement(session, database,
2671:                        session.currentSchema, tableFilter, condition,
2672:                        getSortedSubqueries(), getParameters());
2673:
2674:                return cs;
2675:            }
2676:
2677:            private void getInsertColumnValueExpressions(Table t,
2678:                    Expression[] acve, int len) throws HsqlException {
2679:
2680:                tokenizer.getThis(Token.T_OPENBRACKET);
2681:
2682:                for (int i = 0; i < len; i++) {
2683:                    Expression columnValExpression = parseExpression();
2684:
2685:                    columnValExpression.resolveTables(null);
2686:                    columnValExpression.resolveTypes(session);
2687:
2688:                    acve[i] = columnValExpression;
2689:
2690:                    String token = tokenizer.getSimpleToken();
2691:
2692:                    if (token.equals(Token.T_COMMA)) {
2693:                        continue;
2694:                    }
2695:
2696:                    if (token.equals(Token.T_CLOSEBRACKET)) {
2697:                        if (i == len - 1) {
2698:                            return;
2699:                        } else {
2700:                            break;
2701:                        }
2702:                    }
2703:
2704:                    tokenizer.throwUnexpected();
2705:                }
2706:
2707:                throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2708:            }
2709:
2710:            /**
2711:             * Retrieves an INSERT_XXX-type CompiledStatement from this parse context.
2712:             */
2713:            CompiledStatement compileInsertStatement() throws HsqlException {
2714:
2715:                clearParameters();
2716:                tokenizer.getThis(Token.T_INTO);
2717:
2718:                HsqlArrayList columnNames;
2719:                boolean[] columnCheckList;
2720:                int[] columnMap;
2721:                int len;
2722:                String token = tokenizer.getName();
2723:                String schema = session.getSchemaName(tokenizer
2724:                        .getLongNameFirst());
2725:                Table table = database.schemaManager.getTable(session, token,
2726:                        schema);
2727:
2728:                checkTableWriteAccess(table, UserManager.INSERT);
2729:
2730:                columnNames = null;
2731:                columnCheckList = null;
2732:                columnMap = table.getColumnMap();
2733:                len = table.getColumnCount();
2734:
2735:                int brackets = parseOpenBrackets();
2736:
2737:                token = tokenizer.getString();
2738:
2739:                if (brackets == 1 && !tokenizer.wasThis(Token.T_SELECT)) {
2740:                    brackets = 0;
2741:
2742:                    tokenizer.back();
2743:
2744:                    columnNames = getColumnNames(database, table, tokenizer,
2745:                            false);
2746:
2747:                    if (columnNames.size() > len) {
2748:                        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2749:                    }
2750:
2751:                    len = columnNames.size();
2752:                    columnCheckList = table.getNewColumnCheckList();
2753:                    columnMap = new int[len];
2754:
2755:                    for (int i = 0; i < len; i++) {
2756:                        int ci = table.getColumnNr((String) columnNames.get(i));
2757:
2758:                        columnMap[i] = ci;
2759:                        columnCheckList[ci] = true;
2760:                    }
2761:
2762:                    token = tokenizer.getSimpleToken();
2763:                } else if (!tokenizer.wasSimpleToken()) {
2764:                    tokenizer.throwUnexpected();
2765:                }
2766:
2767:                int command = Token.get(token);
2768:
2769:                switch (command) {
2770:
2771:                case Token.VALUES: {
2772:                    Expression[] acve = new Expression[len];
2773:
2774:                    getInsertColumnValueExpressions(table, acve, len);
2775:
2776:                    CompiledStatement cs = new CompiledStatement(
2777:                            session.currentSchema, table, columnMap, acve,
2778:                            columnCheckList, getSortedSubqueries(),
2779:                            getParameters());
2780:
2781:                    return cs;
2782:                }
2783:                case Token.OPENBRACKET: {
2784:                    brackets = parseOpenBrackets() + 1;
2785:
2786:                    tokenizer.getThis(Token.T_SELECT);
2787:                }
2788:                case Token.SELECT: {
2789:
2790:                    // accept ORDER BY or ORDRY BY with LIMIT
2791:                    Select select = parseSelect(brackets, true, false, true,
2792:                            true);
2793:
2794:                    if (len != select.iResultLen) {
2795:                        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2796:                    }
2797:
2798:                    CompiledStatement cs = new CompiledStatement(session,
2799:                            database, session.currentSchema, table, columnMap,
2800:                            columnCheckList, select, getSortedSubqueries(),
2801:                            getParameters());
2802:
2803:                    return cs;
2804:                }
2805:                default: {
2806:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
2807:                }
2808:                }
2809:            }
2810:
2811:            /**
2812:             * Retrieves a SELECT-type CompiledStatement from this parse context.
2813:             */
2814:            CompiledStatement compileSelectStatement(int brackets)
2815:                    throws HsqlException {
2816:
2817:                clearParameters();
2818:
2819:                Select select = parseSelect(brackets, true, true, false, true);
2820:
2821:                if (select.sIntoTable != null) {
2822:                    String name = select.sIntoTable.name;
2823:                    String schema = select.sIntoTable.schema.name;
2824:
2825:                    if (database.schemaManager.findUserTable(session, name,
2826:                            schema) != null) {
2827:                        throw Trace.error(Trace.TABLE_ALREADY_EXISTS, name);
2828:                    }
2829:                }
2830:
2831:                CompiledStatement cs = new CompiledStatement(session, database,
2832:                        session.currentSchema, select, getSortedSubqueries(),
2833:                        getParameters());
2834:
2835:                return cs;
2836:            }
2837:
2838:            /**
2839:             * Retrieves an UPDATE-type CompiledStatement from this parse context.
2840:             */
2841:            CompiledStatement compileUpdateStatement() throws HsqlException {
2842:
2843:                String token;
2844:                Table table;
2845:                int[] colList;
2846:                Expression[] exprList;
2847:                int len;
2848:                Expression cve;
2849:                Expression condition;
2850:
2851:                clearParameters();
2852:
2853:                TableFilter tableFilter = parseSimpleTableFilter(UserManager.UPDATE);
2854:
2855:                table = tableFilter.filterTable;
2856:
2857:                tokenizer.getThis(Token.T_SET);
2858:
2859:                colList = table.getNewColumnMap();
2860:                exprList = new Expression[colList.length];
2861:                len = 0;
2862:                token = null;
2863:
2864:                do {
2865:                    int ci = table.getColumnNr(tokenizer.getName());
2866:                    String tablename = tokenizer.getLongNameFirst();
2867:
2868:                    if (tablename != null
2869:                            && !tableFilter.getName().equals(tablename)) {
2870:                        throw Trace.error(Trace.TABLE_NOT_FOUND);
2871:                    }
2872:
2873:                    tokenizer.getThis(Token.T_EQUALS);
2874:
2875:                    cve = parseExpression();
2876:
2877:                    if (len == colList.length) {
2878:
2879:                        // too many (repeat) assignments
2880:                        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2881:                    }
2882:
2883:                    colList[len] = ci;
2884:                    exprList[len] = cve;
2885:                    token = tokenizer.getSimpleToken();
2886:
2887:                    len++;
2888:                } while (token.equals(Token.T_COMMA));
2889:
2890:                condition = null;
2891:
2892:                if (token.equals(Token.T_WHERE)) {
2893:                    condition = parseExpression();
2894:                } else {
2895:                    tokenizer.back();
2896:                }
2897:
2898:                colList = (int[]) ArrayUtil.resizeArray(colList, len);
2899:                exprList = (Expression[]) ArrayUtil.resizeArray(exprList, len);
2900:
2901:                CompiledStatement cs = new CompiledStatement(session, database,
2902:                        session.currentSchema, tableFilter, colList, exprList,
2903:                        condition, getSortedSubqueries(), getParameters());
2904:
2905:                return cs;
2906:            }
2907:
2908:            int parseOpenBracketsSelect() throws HsqlException {
2909:
2910:                int count = parseOpenBrackets();
2911:
2912:                tokenizer.getThis(Token.T_SELECT);
2913:
2914:                return count;
2915:            }
2916:
2917:            int parseOpenBrackets() throws HsqlException {
2918:
2919:                int count = 0;
2920:
2921:                while (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
2922:                    count++;
2923:                }
2924:
2925:                return count;
2926:            }
2927:
2928:            int parseCloseBrackets(int limit) throws HsqlException {
2929:
2930:                int count = 0;
2931:
2932:                while (count < limit
2933:                        && tokenizer.isGetThis(Token.T_CLOSEBRACKET)) {
2934:                    count++;
2935:                }
2936:
2937:                return count;
2938:            }
2939:
2940:            HashMappedList parseColumnList() throws HsqlException {
2941:                return processColumnList(tokenizer, false);
2942:            }
2943:
2944:            static HashMappedList processColumnList(Tokenizer tokenizer,
2945:                    boolean acceptAscDesc) throws HsqlException {
2946:
2947:                HashMappedList list;
2948:                String token;
2949:
2950:                list = new HashMappedList();
2951:
2952:                tokenizer.getThis(Token.T_OPENBRACKET);
2953:
2954:                while (true) {
2955:                    token = tokenizer.getSimpleName();
2956:
2957:                    boolean result = list.add(token, null);
2958:
2959:                    if (!result) {
2960:                        throw Trace.error(Trace.COLUMN_ALREADY_EXISTS, token);
2961:                    }
2962:
2963:                    token = tokenizer.getSimpleToken();
2964:
2965:                    if (acceptAscDesc
2966:                            && (token.equals(Token.T_DESC) || token
2967:                                    .equals(Token.T_ASC))) {
2968:                        token = tokenizer.getSimpleToken(); // OJ: eat it up
2969:                    }
2970:
2971:                    if (token.equals(Token.T_COMMA)) {
2972:                        continue;
2973:                    }
2974:
2975:                    if (token.equals(Token.T_CLOSEBRACKET)) {
2976:                        break;
2977:                    }
2978:
2979:                    throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
2980:                }
2981:
2982:                return list;
2983:            }
2984:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.