Source Code Cross Referenced for Expression.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 org.hsqldb.HsqlNameManager.HsqlName;
0069:        import org.hsqldb.index.RowIterator;
0070:        import org.hsqldb.lib.HashSet;
0071:        import org.hsqldb.lib.HsqlArrayList;
0072:        import org.hsqldb.store.ValuePool;
0073:
0074:        // fredt@users 20020215 - patch 1.7.0 by fredt
0075:        // to preserve column size etc. when SELECT INTO TABLE is used
0076:        // tony_lai@users 20021020 - patch 1.7.2 - improved aggregates and HAVING
0077:        // fredt@users 20021112 - patch 1.7.2 by Nitin Chauhan - use of switch
0078:        // rewrite of the majority of multiple if(){}else{} chains with switch(){}
0079:        // vorburger@users 20021229 - patch 1.7.2 - null handling
0080:        // boucherb@users 200307?? - patch 1.7.2 - resolve param nodes
0081:        // boucherb@users 200307?? - patch 1.7.2 - compress constant expr during resolve
0082:        // boucherb@users 200307?? - patch 1.7.2 - eager pmd and rsmd
0083:        // boucherb@users 20031005 - patch 1.7.2 - optimised LIKE
0084:        // boucherb@users 20031005 - patch 1.7.2 - improved IN value lists
0085:        // fredt@users 20031012 - patch 1.7.2 - better OUTER JOIN implementation
0086:        // thomasm@users 20041001 - patch 1.7.3 - BOOLEAN undefined handling
0087:        // fredt@users 200412xx - patch 1.7.2 - evaluation of time functions
0088:        // boucherb@users 20050516 - patch 1.8.0 - remove DITypeInfo usage for faster
0089:        //                                         statement compilation
0090:
0091:        /**
0092:         * Expression class.
0093:         *
0094:         * The core functionality of this class was inherited from HypersonicSQL and
0095:         * extensively rewritten and extended in successive versions of HSQLDB.
0096:         *
0097:         * @author Thomas Mueller (Hypersonic SQL Group)
0098:         * @version    1.8.0
0099:         * @since Hypersonic SQL
0100:         */
0101:
0102:        /** @todo - fredt - constant TRUE and FALSE type expressions have valueData of
0103:         * type BOOLEAN, while computed expressions have no valueData; this should be
0104:         * normalised in future
0105:         */
0106:        public class Expression {
0107:
0108:            // leaf types
0109:            static final int VALUE = 1, COLUMN = 2, QUERY = 3,
0110:                    TRUE = 4,
0111:                    FALSE = -4, // arbitrary
0112:                    VALUELIST = 5, ASTERISK = 6, FUNCTION = 7, LIMIT = 8,
0113:                    ROW = 9;
0114:
0115:            // boucherb@users 20020410 - parametric compiled statements
0116:            // new leaf type
0117:            static final int PARAM = 9;
0118:
0119:            // --
0120:            // operations
0121:            static final int NEGATE = 10, ADD = 11, SUBTRACT = 12,
0122:                    MULTIPLY = 13, DIVIDE = 14, CONCAT = 15;
0123:
0124:            // logical operations
0125:            static final int NOT = 20, EQUAL = 21, BIGGER_EQUAL = 22,
0126:                    BIGGER = 23, SMALLER = 24, SMALLER_EQUAL = 25,
0127:                    NOT_EQUAL = 26, LIKE = 27, AND = 28, OR = 29, IN = 30,
0128:                    EXISTS = 31, ALL = 32, ANY = 33, IS_NULL = 34;
0129:
0130:            // aggregate functions
0131:            static final int COUNT = 40, SUM = 41, MIN = 42, MAX = 43,
0132:                    AVG = 44, EVERY = 45, SOME = 46, STDDEV_POP = 47,
0133:                    STDDEV_SAMP = 48, VAR_POP = 49, VAR_SAMP = 50;
0134:
0135:            // system functions
0136:            static final int IFNULL = 60, CONVERT = 61, CASEWHEN = 62,
0137:                    EXTRACT = 63, POSITION = 64, TRIM = 65, SUBSTRING = 66,
0138:                    NULLIF = 67, CASE = 68, COALESCE = 69, ALTERNATIVE = 70,
0139:                    SEQUENCE = 71;
0140:
0141:            // temporary used during parsing
0142:            static final int PLUS = 100, OPEN = 101, CLOSE = 102, SELECT = 103,
0143:                    COMMA = 104, BETWEEN = 106, CAST = 107, END = 108,
0144:                    IS = 109, WHEN = 110, THEN = 111, ELSE = 112,
0145:                    ENDWHEN = 113, DISTINCT = 114, VIEW = 115;
0146:
0147:            // used inside brackets for system functions
0148:            static final int AS = 122, FOR = 123, FROM = 124, BOTH = 125,
0149:                    LEADING = 126, TRAILING = 127, YEAR = 128, MONTH = 129,
0150:                    DAY = 130, HOUR = 131, MINUTE = 132, SECOND = 133,
0151:                    TIMEZONE_HOUR = 134, T_TIMEZONE_MINUTE = 135, DOW = 136;
0152:            static final HashSet SQL_EXTRACT_FIELD_NAMES = new HashSet();
0153:            static final HashSet SQL_TRIM_SPECIFICATION = new HashSet();
0154:
0155:            static {
0156:                SQL_EXTRACT_FIELD_NAMES.addAll(new Object[] { Token.T_YEAR,
0157:                        Token.T_MONTH, Token.T_DAY, Token.T_HOUR,
0158:                        Token.T_MINUTE, Token.T_SECOND, Token.T_TIMEZONE_HOUR,
0159:                        Token.T_TIMEZONE_MINUTE, Token.T_DOW });
0160:                SQL_TRIM_SPECIFICATION.addAll(new Object[] { Token.T_LEADING,
0161:                        Token.T_TRAILING, Token.T_BOTH });
0162:            }
0163:
0164:            private static final int AGGREGATE_SELF = -1;
0165:            private static final int AGGREGATE_NONE = 0;
0166:            private static final int AGGREGATE_LEFT = 1;
0167:            private static final int AGGREGATE_RIGHT = 2;
0168:            private static final int AGGREGATE_BOTH = 3;
0169:            private static final int AGGREGATE_FUNCTION = 4;
0170:
0171:            // type
0172:            int exprType;
0173:            private int aggregateSpec = AGGREGATE_NONE;
0174:
0175:            // nodes
0176:            Expression eArg, eArg2;
0177:
0178:            // VALUE
0179:            Object valueData;
0180:            private int dataType;
0181:
0182:            // VALUE LIST NEW
0183:            HashSet hList;
0184:            Expression[] valueList;
0185:            private boolean isFixedConstantValueList;
0186:
0187:            // QUERY - in single value selects, IN or EXISTS predicates
0188:            SubQuery subQuery;
0189:            boolean isQueryCorrelated;
0190:
0191:            // FUNCTION
0192:            Function function;
0193:
0194:            // LIKE
0195:            private Like likeObject;
0196:
0197:            // COLUMN
0198:            private String catalog;
0199:            private String schema;
0200:            private String tableName;
0201:            private String columnName;
0202:            private TableFilter tableFilter; // null if not yet resolved
0203:            TableFilter outerFilter; // defined if this is part of an OUTER JOIN condition tree
0204:
0205:            // COLUMN
0206:            private int columnIndex;
0207:            private boolean columnQuoted;
0208:            private int precision;
0209:            private int scale;
0210:            private String columnAlias; // if it is a column of a select column list
0211:            private boolean aliasQuoted;
0212:
0213:            //
0214:            private boolean isDescending; // if it is a column in a order by
0215:            int joinedTableColumnIndex = -1; // >= 0 when it is used for order by
0216:            boolean isDistinctAggregate;
0217:
0218:            // PARAM
0219:            private boolean isParam;
0220:
0221:            // does Expression stem from a JOIN <table> ON <expression>
0222:            boolean isInJoin;
0223:
0224:            //
0225:            static final Integer INTEGER_0 = ValuePool.getInt(0);
0226:            static final Integer INTEGER_1 = ValuePool.getInt(1);
0227:
0228:            /**
0229:             * Creates a new boolean expression
0230:             * @param b boolean constant
0231:             */
0232:            Expression(boolean b) {
0233:                exprType = b ? TRUE : FALSE;
0234:            }
0235:
0236:            /**
0237:             * Creates a new FUNCTION expression
0238:             * @param f function
0239:             */
0240:            Expression(Function f) {
0241:
0242:                exprType = FUNCTION;
0243:                function = f;
0244:
0245:                if (f.hasAggregate) {
0246:                    aggregateSpec = AGGREGATE_FUNCTION;
0247:                }
0248:            }
0249:
0250:            /**
0251:             * Creates a new SEQUENCE expression
0252:             * @param sequence number sequence
0253:             */
0254:            Expression(NumberSequence sequence) {
0255:
0256:                exprType = SEQUENCE;
0257:                valueData = sequence;
0258:                dataType = sequence.getType();
0259:            }
0260:
0261:            /**
0262:             * Copy Constructor. Used by TableFilter to move a condition to a filter.
0263:             * @param e source expression
0264:             */
0265:            Expression(Expression e) {
0266:
0267:                exprType = e.exprType;
0268:                dataType = e.dataType;
0269:                eArg = e.eArg;
0270:                eArg2 = e.eArg2;
0271:                isInJoin = e.isInJoin;
0272:
0273:                //
0274:                likeObject = e.likeObject;
0275:                subQuery = e.subQuery;
0276:                function = e.function;
0277:
0278:                checkAggregate();
0279:            }
0280:
0281:            /**
0282:             * Creates a new QUERY expression
0283:             * @param sq subquery
0284:             */
0285:            Expression(SubQuery sq) {
0286:                exprType = QUERY;
0287:                subQuery = sq;
0288:            }
0289:
0290:            /**
0291:             * Creates a new VALUELIST expression
0292:             * @param valueList array of Expression
0293:             */
0294:            Expression(Expression[] valueList) {
0295:                exprType = VALUELIST;
0296:                this .valueList = valueList;
0297:            }
0298:
0299:            /**
0300:             * Creates a new binary (or unary) operation expression
0301:             *
0302:             * @param type operator type
0303:             * @param e operand 1
0304:             * @param e2 operand 2
0305:             */
0306:            Expression(int type, Expression e, Expression e2) {
0307:
0308:                exprType = type;
0309:                eArg = e;
0310:                eArg2 = e2;
0311:
0312:                checkAggregate();
0313:            }
0314:
0315:            /**
0316:             * creates a CONVERT expression
0317:             */
0318:            Expression(Expression e, int dataType, int precision, int scale) {
0319:
0320:                this .exprType = CONVERT;
0321:                this .eArg = e;
0322:                this .dataType = dataType;
0323:                this .precision = precision;
0324:                this .scale = scale;
0325:                this .columnAlias = e.columnAlias;
0326:                this .aliasQuoted = e.aliasQuoted;
0327:
0328:                checkAggregate();
0329:            }
0330:
0331:            /**
0332:             * Creates a new LIKE expression
0333:             *
0334:             * @param e operand 1
0335:             * @param e2 operand 2
0336:             * @param escape escape character
0337:             */
0338:            Expression(Expression e, Expression e2, Character escape,
0339:                    boolean hasCollation) {
0340:
0341:                exprType = LIKE;
0342:                eArg = e;
0343:                eArg2 = e2;
0344:                likeObject = new Like(escape, hasCollation);
0345:
0346:                checkAggregate();
0347:            }
0348:
0349:            /**
0350:             * Creates a new ASTERISK or COLUMN expression
0351:             * @param table table
0352:             * @param column column
0353:             */
0354:            Expression(String schema, String table, String column) {
0355:
0356:                this .schema = schema;
0357:                tableName = table;
0358:
0359:                if (column == null) {
0360:                    exprType = ASTERISK;
0361:                } else {
0362:                    exprType = COLUMN;
0363:                    columnName = column;
0364:                }
0365:            }
0366:
0367:            /**
0368:             * Creates a new ASTERIX or possibly quoted COLUMN expression
0369:             * @param table table
0370:             * @param column column name
0371:             * @param isquoted boolean
0372:             */
0373:            Expression(String table, String column, boolean isquoted) {
0374:
0375:                tableName = table;
0376:
0377:                if (column == null) {
0378:                    exprType = ASTERISK;
0379:                } else {
0380:                    exprType = COLUMN;
0381:                    columnName = column;
0382:                    columnQuoted = isquoted;
0383:                }
0384:            }
0385:
0386:            Expression(TableFilter filter, Column column) {
0387:
0388:                schema = filter.filterTable.tableName.schema.name;
0389:                tableName = filter.getName();
0390:
0391:                if (column == null) {
0392:                    exprType = ASTERISK;
0393:                } else {
0394:                    exprType = COLUMN;
0395:                    columnName = column.columnName.name;
0396:                    columnQuoted = column.columnName.isNameQuoted;
0397:                    dataType = column.getType();
0398:                }
0399:            }
0400:
0401:            /**
0402:             * Creates a new VALUE expression
0403:             *
0404:             * @param datatype data type
0405:             * @param o data
0406:             */
0407:            Expression(int datatype, Object o) {
0408:
0409:                exprType = VALUE;
0410:                dataType = datatype;
0411:                valueData = o;
0412:            }
0413:
0414:            /**
0415:             * Creates a new (possibly PARAM) VALUE expression
0416:             *
0417:             * @param datatype initial datatype
0418:             * @param o initial value
0419:             * @param isParam true if this is to be a PARAM VALUE expression
0420:             */
0421:            Expression(int datatype, Object o, boolean isParam) {
0422:
0423:                this (datatype, o);
0424:
0425:                this .isParam = isParam;
0426:
0427:                if (isParam) {
0428:                    paramMode = PARAM_IN;
0429:                }
0430:            }
0431:
0432:            boolean isTypeEqual(Expression other) {
0433:                return dataType == other.dataType
0434:                        && precision == other.precision && scale == other.scale;
0435:            }
0436:
0437:            private void checkAggregate() {
0438:
0439:                if (isAggregate(exprType)) {
0440:                    aggregateSpec = AGGREGATE_SELF;
0441:                } else {
0442:                    aggregateSpec = AGGREGATE_NONE;
0443:
0444:                    if ((eArg != null) && eArg.isAggregate()) {
0445:                        aggregateSpec += AGGREGATE_LEFT;
0446:                    }
0447:
0448:                    if ((eArg2 != null) && eArg2.isAggregate()) {
0449:                        aggregateSpec += AGGREGATE_RIGHT;
0450:                    }
0451:                }
0452:            }
0453:
0454:            public String describe(Session session) {
0455:                return describe(session, 0);
0456:            }
0457:
0458:            static String getContextDDL(Expression expression)
0459:                    throws HsqlException {
0460:
0461:                String ddl = expression.getDDL();
0462:
0463:                if (expression.exprType != VALUE
0464:                        && expression.exprType != COLUMN
0465:                        && expression.exprType != FUNCTION
0466:                        && expression.exprType != ALTERNATIVE
0467:                        && expression.exprType != CASEWHEN
0468:                        && expression.exprType != CONVERT) {
0469:                    StringBuffer temp = new StringBuffer();
0470:
0471:                    ddl = temp.append('(').append(ddl).append(')').toString();
0472:                }
0473:
0474:                return ddl;
0475:            }
0476:
0477:            /**
0478:             *  returns the complete name of the column represented by the expression
0479:             *
0480:             *  If an alias is known for the column's table, this alias will precede the
0481:             *  column name, except it's "SYSTEM_SUBQUERY".
0482:             *  If no alias is known, the column's table will be asked for its
0483:             *  statementName, which then will precede the column name.
0484:             */
0485:            String getColumnDDL() throws HsqlException {
0486:
0487:                Trace.doAssert(exprType == COLUMN);
0488:
0489:                StringBuffer buf = new StringBuffer();
0490:
0491:                Table table = tableFilter.getTable();
0492:
0493:                if (tableName != null) {
0494:                    if (!tableName.equals("SYSTEM_SUBQUERY"))
0495:                        buf.append('"').append(tableName).append('"').append(
0496:                                '.');
0497:                } else
0498:                    buf.append(table.tableName.statementName).append('.');
0499:
0500:                buf
0501:                        .append(table.getColumn(columnIndex).columnName.statementName);
0502:
0503:                return buf.toString();
0504:            }
0505:
0506:            /**
0507:             * For use with CHECK constraints. Under development.
0508:             *
0509:             * Currently supports a subset of expressions and is suitable for CHECK
0510:             * search conditions that refer only to the inserted/updated row.
0511:             *
0512:             * For full DDL reporting of VIEW select queries and CHECK search
0513:             * conditions, future improvements here are dependent upon improvements to
0514:             * SELECT query parsing, so that it is performed in a number of passes.
0515:             * An early pass should result in the query turned into an Expression tree
0516:             * that contains the information in the original SQL without any
0517:             * alterations, and with tables and columns all resolved. This Expression
0518:             * can then be preserved for future use. Table and column names that
0519:             * are not user-defined aliases should be kept as the HsqlName structures
0520:             * so that table or column renaming is reflected in the precompiled
0521:             * query.
0522:             *
0523:             * @return DDL
0524:             * @throws HsqlException
0525:             */
0526:            String getDDL() throws HsqlException {
0527:
0528:                StringBuffer buf = new StringBuffer(64);
0529:                String left = null;
0530:                String right = null;
0531:
0532:                if (eArg != null) {
0533:                    left = Expression.getContextDDL(eArg);
0534:                }
0535:
0536:                if (eArg2 != null) {
0537:                    right = Expression.getContextDDL(eArg2);
0538:                }
0539:
0540:                switch (exprType) {
0541:
0542:                case FUNCTION:
0543:                    return function.getDLL();
0544:
0545:                case VALUE:
0546:                    try {
0547:                        return isParam ? Token.T_QUESTION : Column
0548:                                .createSQLString(valueData, dataType);
0549:                    } catch (HsqlException e) {
0550:                    }
0551:
0552:                    return buf.toString();
0553:
0554:                case COLUMN:
0555:
0556:                    // this is a limited solution
0557:                    Table table = tableFilter.getTable();
0558:
0559:                    if (tableName != null) {
0560:                        buf.append(table.tableName.statementName);
0561:                        buf.append('.');
0562:                    }
0563:
0564:                    buf
0565:                            .append(table.getColumn(columnIndex).columnName.statementName);
0566:
0567:                    return buf.toString();
0568:
0569:                case TRUE:
0570:                    return Token.T_TRUE;
0571:
0572:                case FALSE:
0573:                    return Token.T_FALSE;
0574:
0575:                case VALUELIST:
0576:                    for (int i = 0; i < valueList.length; i++) {
0577:                        buf.append(valueList[i].getDDL());
0578:
0579:                        if (i < valueList.length - 1) {
0580:                            buf.append(',');
0581:                        }
0582:                    }
0583:
0584:                    return buf.toString();
0585:
0586:                case ASTERISK:
0587:                    buf.append('*');
0588:
0589:                    return buf.toString();
0590:
0591:                case NEGATE:
0592:                    buf.append('-').append(left);
0593:
0594:                    return buf.toString();
0595:
0596:                case ADD:
0597:                    buf.append(left).append('+').append(right);
0598:
0599:                    return buf.toString();
0600:
0601:                case SUBTRACT:
0602:                    buf.append(left).append('-').append(right);
0603:
0604:                    return buf.toString();
0605:
0606:                case MULTIPLY:
0607:                    buf.append(left).append('*').append(right);
0608:
0609:                    return buf.toString();
0610:
0611:                case DIVIDE:
0612:                    buf.append(left).append('/').append(right);
0613:
0614:                    return buf.toString();
0615:
0616:                case CONCAT:
0617:                    buf.append(left).append("||").append(right);
0618:
0619:                    return buf.toString();
0620:
0621:                case NOT:
0622:                    if (eArg.exprType == IS_NULL) {
0623:                        buf.append(getContextDDL(eArg.eArg)).append(' ')
0624:                                .append(Token.T_IS).append(' ').append(
0625:                                        Token.T_NOT).append(' ').append(
0626:                                        Token.T_NULL);
0627:
0628:                        return buf.toString();
0629:                    }
0630:
0631:                    buf.append(Token.T_NOT).append(' ').append(left);
0632:
0633:                    return buf.toString();
0634:
0635:                case EQUAL:
0636:                    buf.append(left).append('=').append(right);
0637:
0638:                    return buf.toString();
0639:
0640:                case BIGGER_EQUAL:
0641:                    buf.append(left).append(">=").append(right);
0642:
0643:                    return buf.toString();
0644:
0645:                case BIGGER:
0646:                    buf.append(left).append('>').append(right);
0647:
0648:                    return buf.toString();
0649:
0650:                case SMALLER:
0651:                    buf.append(left).append('<').append(right);
0652:
0653:                    return buf.toString();
0654:
0655:                case SMALLER_EQUAL:
0656:                    buf.append(left).append("<=").append(right);
0657:
0658:                    return buf.toString();
0659:
0660:                case NOT_EQUAL:
0661:                    if (Token.T_NULL.equals(right)) {
0662:                        buf.append(left).append(" IS NOT ").append(right);
0663:                    } else {
0664:                        buf.append(left).append("!=").append(right);
0665:                    }
0666:
0667:                    return buf.toString();
0668:
0669:                case LIKE:
0670:                    buf.append(left).append(' ').append(Token.T_LIKE).append(
0671:                            ' ');
0672:                    buf.append(right);
0673:
0674:                    /** @todo fredt - scripting of non-ascii escapes needs changes to general script logging */
0675:                    if (likeObject.escapeChar != null) {
0676:                        buf.append(' ').append(Token.T_ESCAPE).append(' ')
0677:                                .append('\'');
0678:                        buf.append(likeObject.escapeChar.toString()).append(
0679:                                '\'');
0680:                        buf.append(' ');
0681:                    }
0682:
0683:                    return buf.toString();
0684:
0685:                case AND:
0686:                    buf.append(left).append(' ').append(Token.T_AND)
0687:                            .append(' ').append(right);
0688:
0689:                    return buf.toString();
0690:
0691:                case OR:
0692:                    buf.append(left).append(' ').append(Token.T_OR).append(' ')
0693:                            .append(right);
0694:
0695:                    return buf.toString();
0696:
0697:                case ALL:
0698:                    buf.append(left).append(' ').append(Token.T_ALL)
0699:                            .append(' ').append(right);
0700:
0701:                    return buf.toString();
0702:
0703:                case ANY:
0704:                    buf.append(left).append(' ').append(Token.T_ANY)
0705:                            .append(' ').append(right);
0706:
0707:                    return buf.toString();
0708:
0709:                case IN:
0710:                    buf.append(left).append(' ').append(Token.T_IN).append(' ')
0711:                            .append(right);
0712:
0713:                    return buf.toString();
0714:
0715:                case CONVERT:
0716:                    buf.append(' ').append(Token.T_CONVERT).append('(');
0717:                    buf.append(left).append(',');
0718:                    buf.append(Types.getTypeString(dataType, precision, scale));
0719:                    buf.append(')');
0720:
0721:                    return buf.toString();
0722:
0723:                case CASEWHEN:
0724:                    buf.append(' ').append(Token.T_CASEWHEN).append('(');
0725:                    buf.append(left).append(',').append(right).append(')');
0726:
0727:                    return buf.toString();
0728:
0729:                case IS_NULL:
0730:                    buf.append(left).append(' ').append(Token.T_IS).append(' ')
0731:                            .append(Token.T_NULL);
0732:
0733:                    return buf.toString();
0734:
0735:                case ALTERNATIVE:
0736:                    buf.append(left).append(',').append(right);
0737:
0738:                    return buf.toString();
0739:
0740:                case QUERY:
0741:                    /*
0742:                     buf.append('(');
0743:                     buf.append(subSelect.getDDL());
0744:                     buf.append(')');
0745:                     */
0746:                    break;
0747:
0748:                case EXISTS:
0749:                    buf.append(' ').append(Token.T_EXISTS).append(' ');
0750:                    break;
0751:
0752:                case COUNT:
0753:                    buf.append(' ').append(Token.T_COUNT).append('(');
0754:                    break;
0755:
0756:                case SUM:
0757:                    buf.append(' ').append(Token.T_SUM).append('(');
0758:                    buf.append(left).append(')');
0759:                    break;
0760:
0761:                case MIN:
0762:                    buf.append(' ').append(Token.T_MIN).append('(');
0763:                    buf.append(left).append(')');
0764:                    break;
0765:
0766:                case MAX:
0767:                    buf.append(' ').append(Token.T_MAX).append('(');
0768:                    buf.append(left).append(')');
0769:                    break;
0770:
0771:                case AVG:
0772:                    buf.append(' ').append(Token.T_AVG).append('(');
0773:                    buf.append(left).append(')');
0774:                    break;
0775:
0776:                case EVERY:
0777:                    buf.append(' ').append(Token.T_EVERY).append('(');
0778:                    buf.append(left).append(')');
0779:                    break;
0780:
0781:                case SOME:
0782:                    buf.append(' ').append(Token.T_SOME).append('(');
0783:                    buf.append(left).append(')');
0784:                    break;
0785:
0786:                case STDDEV_POP:
0787:                    buf.append(' ').append(Token.T_STDDEV_POP).append('(');
0788:                    buf.append(left).append(')');
0789:                    break;
0790:
0791:                case STDDEV_SAMP:
0792:                    buf.append(' ').append(Token.T_STDDEV_SAMP).append('(');
0793:                    buf.append(left).append(')');
0794:                    break;
0795:
0796:                case VAR_POP:
0797:                    buf.append(' ').append(Token.T_VAR_POP).append('(');
0798:                    buf.append(left).append(')');
0799:                    break;
0800:
0801:                case VAR_SAMP:
0802:                    buf.append(' ').append(Token.T_VAR_SAMP).append('(');
0803:                    buf.append(left).append(')');
0804:                    break;
0805:                }
0806:
0807:                throw Trace.error(Trace.EXPRESSION_NOT_SUPPORTED);
0808:            }
0809:
0810:            private String describe(Session session, int blanks) {
0811:
0812:                int lIType;
0813:                StringBuffer buf = new StringBuffer(64);
0814:
0815:                buf.append('\n');
0816:
0817:                for (int i = 0; i < blanks; i++) {
0818:                    buf.append(' ');
0819:                }
0820:
0821:                if (oldIType != -1) {
0822:                    buf.append("SET TRUE, WAS: ");
0823:                }
0824:
0825:                lIType = oldIType == -1 ? exprType : oldIType;
0826:
0827:                switch (lIType) {
0828:
0829:                case FUNCTION:
0830:                    buf.append("FUNCTION ");
0831:                    buf.append(function.describe(session));
0832:
0833:                    return buf.toString();
0834:
0835:                case VALUE:
0836:                    if (isParam) {
0837:                        buf.append("PARAM ");
0838:                    }
0839:
0840:                    buf.append("VALUE = ").append(valueData);
0841:                    buf.append(", TYPE = ").append(
0842:                            Types.getTypeString(dataType));
0843:
0844:                    return buf.toString();
0845:
0846:                case COLUMN:
0847:                    buf.append("COLUMN ");
0848:
0849:                    if (tableName != null) {
0850:                        buf.append(tableName);
0851:                        buf.append('.');
0852:                    }
0853:
0854:                    buf.append(columnName);
0855:
0856:                    return buf.toString();
0857:
0858:                case QUERY:
0859:                    buf.append("QUERY ");
0860:                    buf.append(subQuery.select.describe(session));
0861:
0862:                    return buf.toString();
0863:
0864:                case TRUE:
0865:                    buf.append("TRUE ");
0866:                    break;
0867:
0868:                case FALSE:
0869:                    buf.append("FALSE ");
0870:                    break;
0871:
0872:                case VALUELIST:
0873:                    buf.append("VALUELIST ");
0874:                    buf.append(" TYPE = ")
0875:                            .append(Types.getTypeString(dataType));
0876:
0877:                    if (valueList != null) {
0878:                        for (int i = 0; i < valueList.length; i++) {
0879:                            buf.append(valueList[i].describe(session, blanks
0880:                                    + blanks));
0881:                            buf.append(' ');
0882:                        }
0883:                    }
0884:                    break;
0885:
0886:                case ASTERISK:
0887:                    buf.append("* ");
0888:                    break;
0889:
0890:                case NEGATE:
0891:                    buf.append("NEGATE ");
0892:                    break;
0893:
0894:                case ADD:
0895:                    buf.append("ADD ");
0896:                    break;
0897:
0898:                case SUBTRACT:
0899:                    buf.append("SUBTRACT ");
0900:                    break;
0901:
0902:                case MULTIPLY:
0903:                    buf.append("MULTIPLY ");
0904:                    break;
0905:
0906:                case DIVIDE:
0907:                    buf.append("DIVIDE ");
0908:                    break;
0909:
0910:                case CONCAT:
0911:                    buf.append("CONCAT ");
0912:                    break;
0913:
0914:                case NOT:
0915:                    buf.append("NOT ");
0916:                    break;
0917:
0918:                case EQUAL:
0919:                    buf.append("EQUAL ");
0920:                    break;
0921:
0922:                case BIGGER_EQUAL:
0923:                    buf.append("BIGGER_EQUAL ");
0924:                    break;
0925:
0926:                case BIGGER:
0927:                    buf.append("BIGGER ");
0928:                    break;
0929:
0930:                case SMALLER:
0931:                    buf.append("SMALLER ");
0932:                    break;
0933:
0934:                case SMALLER_EQUAL:
0935:                    buf.append("SMALLER_EQUAL ");
0936:                    break;
0937:
0938:                case NOT_EQUAL:
0939:                    buf.append("NOT_EQUAL ");
0940:                    break;
0941:
0942:                case LIKE:
0943:                    buf.append("LIKE ");
0944:                    buf.append(likeObject.describe(session));
0945:                    break;
0946:
0947:                case AND:
0948:                    buf.append("AND ");
0949:                    break;
0950:
0951:                case OR:
0952:                    buf.append("OR ");
0953:                    break;
0954:
0955:                case ALL:
0956:                    buf.append("ALL ");
0957:                    break;
0958:
0959:                case ANY:
0960:                    buf.append("ANY ");
0961:                    break;
0962:
0963:                case IN:
0964:                    buf.append("IN ");
0965:                    break;
0966:
0967:                case IS_NULL:
0968:                    buf.append("IS_NULL ");
0969:                    break;
0970:
0971:                case EXISTS:
0972:                    buf.append("EXISTS ");
0973:                    break;
0974:
0975:                case COUNT:
0976:                    buf.append("COUNT ");
0977:                    break;
0978:
0979:                case SUM:
0980:                    buf.append("SUM ");
0981:                    break;
0982:
0983:                case MIN:
0984:                    buf.append("MIN ");
0985:                    break;
0986:
0987:                case MAX:
0988:                    buf.append("MAX ");
0989:                    break;
0990:
0991:                case AVG:
0992:                    buf.append("AVG ");
0993:                    break;
0994:
0995:                case EVERY:
0996:                    buf.append(Token.T_EVERY).append(' ');
0997:                    break;
0998:
0999:                case SOME:
1000:                    buf.append(Token.T_SOME).append(' ');
1001:                    break;
1002:
1003:                case STDDEV_POP:
1004:                    buf.append(Token.T_STDDEV_POP).append(' ');
1005:                    break;
1006:
1007:                case STDDEV_SAMP:
1008:                    buf.append(Token.T_STDDEV_SAMP).append(' ');
1009:                    break;
1010:
1011:                case VAR_POP:
1012:                    buf.append(Token.T_VAR_POP).append(' ');
1013:                    break;
1014:
1015:                case VAR_SAMP:
1016:                    buf.append(Token.T_VAR_SAMP).append(' ');
1017:                    break;
1018:
1019:                case CONVERT:
1020:                    buf.append("CONVERT ");
1021:                    buf.append(Types.getTypeString(dataType, precision, scale));
1022:                    buf.append(' ');
1023:                    break;
1024:
1025:                case CASEWHEN:
1026:                    buf.append("CASEWHEN ");
1027:                    break;
1028:                }
1029:
1030:                if (isInJoin) {
1031:                    buf.append(" join");
1032:                }
1033:
1034:                if (eArg != null) {
1035:                    buf.append(" arg1=[");
1036:                    buf.append(eArg.describe(session, blanks + 1));
1037:                    buf.append(']');
1038:                }
1039:
1040:                if (eArg2 != null) {
1041:                    buf.append(" arg2=[");
1042:                    buf.append(eArg2.describe(session, blanks + 1));
1043:                    buf.append(']');
1044:                }
1045:
1046:                return buf.toString();
1047:            }
1048:
1049:            /**
1050:             * Set the data type
1051:             *
1052:             *
1053:             * @param type data type
1054:             */
1055:            void setDataType(int type) {
1056:                dataType = type;
1057:            }
1058:
1059:            int oldIType = -1;
1060:
1061:            /**
1062:             * When an Expression is assigned to a TableFilter, a copy is made for use
1063:             * there and the original is set to Expression.TRUE
1064:             *
1065:             */
1066:            void setTrue() {
1067:
1068:                if (oldIType == -1) {
1069:                    oldIType = exprType;
1070:                }
1071:
1072:                exprType = TRUE;
1073:            }
1074:
1075:            void setNull() {
1076:
1077:                isParam = false;
1078:                exprType = VALUE;
1079:                dataType = Types.NULL;
1080:                valueData = null;
1081:                eArg = null;
1082:                eArg2 = null;
1083:            }
1084:
1085:            /**
1086:             * Check if the given expression defines similar operation as this
1087:             * expression. This method is used for ensuring an expression in
1088:             * the ORDER BY clause has a matching column in the SELECT list. This check
1089:             * is necessary with a SELECT DISTINCT query.<br>
1090:             *
1091:             * In the future we may perform the test when evaluating the search
1092:             * condition to get a more accurate match.
1093:             *
1094:             * @param exp expression
1095:             * @return boolean
1096:             */
1097:            public boolean similarTo(Expression exp) {
1098:
1099:                if (exp == null) {
1100:                    return false;
1101:                }
1102:
1103:                if (exp == this ) {
1104:                    return true;
1105:                }
1106:
1107:                /** @todo fredt - equals() method for valueList, subSelect and function are needed */
1108:                return exprType == exp.exprType && dataType == exp.dataType
1109:                        && equals(valueData, exp.valueData)
1110:                        && equals(valueList, exp.valueList)
1111:                        && equals(subQuery, exp.subQuery)
1112:                        && equals(function, exp.function)
1113:                        && equals(tableName, exp.tableName)
1114:                        && equals(columnName, exp.columnName)
1115:                        && similarTo(eArg, exp.eArg)
1116:                        && similarTo(eArg2, exp.eArg2);
1117:            }
1118:
1119:            static boolean equals(Object o1, Object o2) {
1120:                return (o1 == null) ? o2 == null : o1.equals(o2);
1121:            }
1122:
1123:            static boolean equals(Expression[] ae1, Expression[] ae2) {
1124:
1125:                if (ae1 == ae2) {
1126:                    return true;
1127:                }
1128:
1129:                if (ae1.length != ae2.length) {
1130:                    return false;
1131:                }
1132:
1133:                int len = ae1.length;
1134:                boolean equals = true;
1135:
1136:                for (int i = 0; i < len; i++) {
1137:                    Expression e1 = ae1[i];
1138:                    Expression e2 = ae2[i];
1139:
1140:                    equals = (e1 == null) ? e2 == null : e1.equals(e2);
1141:                }
1142:
1143:                return equals;
1144:            }
1145:
1146:            static boolean similarTo(Expression e1, Expression e2) {
1147:                return (e1 == null) ? e2 == null : e1.similarTo(e2);
1148:            }
1149:
1150:            /** @todo fredt - workaround for functions in ORDER BY and GROUP BY needs
1151:             *  checking the argument of the function to ensure they are valid. */
1152:
1153:            /**
1154:             * Check if this expression can be included in a group by clause.
1155:             * <p>
1156:             * It can, if itself is a column expression, and it is not an aggregate
1157:             * expression.
1158:             *
1159:             * @return boolean
1160:             */
1161:            boolean canBeInGroupBy() {
1162:
1163:                if (exprType == FUNCTION) {
1164:                    return true;
1165:                }
1166:
1167:                return isColumn() && (!(isAggregate()));
1168:            }
1169:
1170:            /**
1171:             * Check if this expression can be included in an order by clause.
1172:             * <p>
1173:             * It can, if itself is a column expression.
1174:             *
1175:             * @return boolean
1176:             */
1177:            boolean canBeInOrderBy() {
1178:                return exprType == FUNCTION || joinedTableColumnIndex != -1
1179:                        || isColumn() || isAggregate();
1180:            }
1181:
1182:            /**
1183:             * Check if this expression defines at least one column.
1184:             * <p>
1185:             * It is, if itself is a column expression, or any the argument
1186:             * expressions is a column expression.
1187:             *
1188:             * @return boolean
1189:             */
1190:            private boolean isColumn() {
1191:
1192:                switch (exprType) {
1193:
1194:                case COLUMN:
1195:                    return true;
1196:
1197:                case NEGATE:
1198:                    return eArg.isColumn();
1199:
1200:                case ADD:
1201:                case SUBTRACT:
1202:                case MULTIPLY:
1203:                case DIVIDE:
1204:                case CONCAT:
1205:                    return eArg.isColumn() || eArg2.isColumn();
1206:                }
1207:
1208:                return false;
1209:            }
1210:
1211:            /**
1212:             * Collect column name used in this expression.
1213:             *
1214:             * @param columnNames set to be filled
1215:             * @return true if a column name is used in this expression
1216:             */
1217:            boolean collectColumnName(HashSet columnNames) {
1218:
1219:                boolean result = exprType == COLUMN;
1220:
1221:                if (result) {
1222:                    columnNames.add(columnName);
1223:                }
1224:
1225:                return result;
1226:            }
1227:
1228:            /**
1229:             * Collect all column names used in this expression or any of nested
1230:             * expression.
1231:             *
1232:             * @param columnNames set to be filled
1233:             */
1234:            void collectAllColumnNames(HashSet columnNames) {
1235:
1236:                if (!collectColumnName(columnNames)) {
1237:                    if (eArg != null) {
1238:                        eArg.collectAllColumnNames(columnNames);
1239:                    }
1240:
1241:                    if (eArg2 != null) {
1242:                        eArg2.collectAllColumnNames(columnNames);
1243:                    }
1244:                }
1245:            }
1246:
1247:            /**
1248:             * Check if this expression defines a constant value.
1249:             * <p>
1250:             * It does, if it is a constant value expression, or all the argument
1251:             * expressions define constant values.
1252:             *
1253:             * @return boolean
1254:             */
1255:            boolean isConstant() {
1256:
1257:                switch (exprType) {
1258:
1259:                case VALUE:
1260:                    return true;
1261:
1262:                case NEGATE:
1263:                    return eArg.isConstant();
1264:
1265:                case ADD:
1266:                case SUBTRACT:
1267:                case MULTIPLY:
1268:                case DIVIDE:
1269:                case CONCAT:
1270:                    return eArg.isConstant() && eArg2.isConstant();
1271:                }
1272:
1273:                return false;
1274:            }
1275:
1276:            /**
1277:             * Check if this expression can be included as a result column in an
1278:             * aggregated select statement.
1279:             * <p>
1280:             * It can, if itself is an aggregate expression, or it results a constant
1281:             * value.
1282:             *
1283:             * @return boolean
1284:             */
1285:            boolean canBeInAggregate() {
1286:                return isAggregate() || isConstant();
1287:            }
1288:
1289:            /**
1290:             *  Is this (indirectly) an aggregate expression
1291:             *
1292:             *  @return boolean
1293:             */
1294:            boolean isAggregate() {
1295:                return aggregateSpec != AGGREGATE_NONE;
1296:            }
1297:
1298:            /**
1299:             *  Is this directly an aggregate expression
1300:             *
1301:             *
1302:             *  @return boolean
1303:             */
1304:            boolean isSelfAggregate() {
1305:                return aggregateSpec == AGGREGATE_SELF;
1306:            }
1307:
1308:            static boolean isAggregate(int type) {
1309:
1310:                switch (type) {
1311:
1312:                case COUNT:
1313:                case MAX:
1314:                case MIN:
1315:                case SUM:
1316:                case AVG:
1317:                case EVERY:
1318:                case SOME:
1319:                case STDDEV_POP:
1320:                case STDDEV_SAMP:
1321:                case VAR_POP:
1322:                case VAR_SAMP:
1323:                    return true;
1324:                }
1325:
1326:                return false;
1327:            }
1328:
1329:            // tony_lai@users having
1330:
1331:            /**
1332:             *  Checks for conditional expression.
1333:             *
1334:             *
1335:             *  @return boolean
1336:             */
1337:            boolean isConditional() {
1338:
1339:                switch (exprType) {
1340:
1341:                case TRUE:
1342:                case FALSE:
1343:                case EQUAL:
1344:                case BIGGER_EQUAL:
1345:                case BIGGER:
1346:                case SMALLER:
1347:                case SMALLER_EQUAL:
1348:                case NOT_EQUAL:
1349:                case LIKE:
1350:                case IN:
1351:                case EXISTS:
1352:                case IS_NULL:
1353:                    return true;
1354:
1355:                case NOT:
1356:                    return eArg.isConditional();
1357:
1358:                case AND:
1359:                case OR:
1360:                    return eArg.isConditional() && eArg2.isConditional();
1361:
1362:                default:
1363:                    return false;
1364:                }
1365:            }
1366:
1367:            /**
1368:             * Collects all expressions that must be in the GROUP BY clause, for a
1369:             * grouped select statement.
1370:             *
1371:             * @param colExps expression list
1372:             */
1373:            void collectInGroupByExpressions(HsqlArrayList colExps) {
1374:
1375:                if (!(isConstant() || isSelfAggregate())) {
1376:                    if (isColumn()) {
1377:                        colExps.add(this );
1378:                    } else if (exprType == FUNCTION) {
1379:
1380:                        //                function.collectInGroupByExpressions(colExps);
1381:                    } else if (exprType == CASEWHEN) {
1382:                        eArg2.collectInGroupByExpressions(colExps);
1383:                    } else {
1384:                        if (eArg != null) {
1385:                            eArg.collectInGroupByExpressions(colExps);
1386:                        }
1387:
1388:                        if (eArg2 != null) {
1389:                            eArg2.collectInGroupByExpressions(colExps);
1390:                        }
1391:                    }
1392:                }
1393:            }
1394:
1395:            /**
1396:             * Set an ORDER BY column expression DESC
1397:             *
1398:             */
1399:            void setDescending() {
1400:                isDescending = true;
1401:            }
1402:
1403:            /**
1404:             * Is an ORDER BY column expression DESC
1405:             *
1406:             *
1407:             * @return boolean
1408:             */
1409:            boolean isDescending() {
1410:                return isDescending;
1411:            }
1412:
1413:            /**
1414:             * Set the column alias and whether the name is quoted
1415:             *
1416:             * @param s alias
1417:             * @param isquoted boolean
1418:             */
1419:            void setAlias(String s, boolean isquoted) {
1420:                columnAlias = s;
1421:                aliasQuoted = isquoted;
1422:            }
1423:
1424:            /**
1425:             * Change the column name
1426:             *
1427:             * @param newname name
1428:             * @param isquoted quoted
1429:             */
1430:            void setColumnName(String newname, boolean isquoted) {
1431:                columnName = newname;
1432:                columnQuoted = isquoted;
1433:            }
1434:
1435:            /**
1436:             * Change the table name
1437:             *
1438:             * @param newname table name for column expression
1439:             */
1440:            void setTableName(String newname) {
1441:                tableName = newname;
1442:            }
1443:
1444:            /**
1445:             * Return the user defined alias or null if none
1446:             *
1447:             * @return alias
1448:             */
1449:            String getDefinedAlias() {
1450:                return columnAlias;
1451:            }
1452:
1453:            /**
1454:             * Get the column alias
1455:             *
1456:             *
1457:             * @return alias
1458:             */
1459:            String getAlias() {
1460:
1461:                if (columnAlias != null) {
1462:                    return columnAlias;
1463:                }
1464:
1465:                if (exprType == COLUMN) {
1466:                    return columnName;
1467:                }
1468:
1469:                return "";
1470:            }
1471:
1472:            /**
1473:             * Is a column alias quoted
1474:             *
1475:             * @return boolean
1476:             */
1477:            boolean isAliasQuoted() {
1478:
1479:                if (columnAlias != null) {
1480:                    return aliasQuoted;
1481:                }
1482:
1483:                if (exprType == COLUMN) {
1484:                    return columnQuoted;
1485:                }
1486:
1487:                return false;
1488:            }
1489:
1490:            /**
1491:             * Returns the type of expression
1492:             *
1493:             *
1494:             * @return type
1495:             */
1496:            int getType() {
1497:                return exprType;
1498:            }
1499:
1500:            /**
1501:             * Returns the left node
1502:             *
1503:             *
1504:             * @return argument
1505:             */
1506:            Expression getArg() {
1507:                return eArg;
1508:            }
1509:
1510:            /**
1511:             * Returns the right node
1512:             *
1513:             *
1514:             * @return argument
1515:             */
1516:            Expression getArg2() {
1517:                return eArg2;
1518:            }
1519:
1520:            /**
1521:             * Returns the table filter for a COLUMN expression
1522:             *
1523:             * @return table filter
1524:             */
1525:            TableFilter getFilter() {
1526:                return tableFilter;
1527:            }
1528:
1529:            /**
1530:             * Final check for all expressions.
1531:             *
1532:             * @param check boolean
1533:             * @return boolean
1534:             * @throws HsqlException
1535:             */
1536:            boolean checkResolved(boolean check) throws HsqlException {
1537:
1538:                boolean result = true;
1539:
1540:                if (eArg != null) {
1541:                    result = result && eArg.checkResolved(check);
1542:                }
1543:
1544:                if (eArg2 != null) {
1545:                    result = result && eArg2.checkResolved(check);
1546:                }
1547:
1548:                if (subQuery != null && subQuery.select != null) {
1549:                    result = result && subQuery.select.checkResolved(check);
1550:                }
1551:
1552:                if (function != null) {
1553:                    result = result && function.checkResolved(check);
1554:                }
1555:
1556:                if (valueList != null) {
1557:                    for (int i = 0; i < valueList.length; i++) {
1558:                        result = result && valueList[i].checkResolved(check);
1559:                    }
1560:                }
1561:
1562:                if (exprType == COLUMN) {
1563:                    if (tableFilter == null) {
1564:
1565:                        // if an order by column alias
1566:                        result = joinedTableColumnIndex != -1;
1567:
1568:                        if (!result && check) {
1569:                            String err = tableName == null ? columnName
1570:                                    : tableName + "." + columnName;
1571:
1572:                            throw Trace.error(Trace.COLUMN_NOT_FOUND, err);
1573:                        }
1574:                    } else {
1575:                        tableFilter.usedColumns[this .columnIndex] = true;
1576:                    }
1577:                }
1578:
1579:                return result;
1580:            }
1581:
1582:            /**
1583:             * Resolve the table names for columns and throws if a column remains
1584:             * unresolved.
1585:             *
1586:             * @param filters list of filters
1587:             *
1588:             * @throws HsqlException
1589:             */
1590:            void checkTables(HsqlArrayList filters) throws HsqlException {
1591:
1592:                if (filters == null || exprType == Expression.VALUE) {
1593:                    return;
1594:                }
1595:
1596:                if (eArg != null) {
1597:                    eArg.checkTables(filters);
1598:                }
1599:
1600:                if (eArg2 != null) {
1601:                    eArg2.checkTables(filters);
1602:                }
1603:
1604:                switch (exprType) {
1605:
1606:                case COLUMN:
1607:                    boolean found = false;
1608:                    int len = filters.size();
1609:
1610:                    for (int j = 0; j < len; j++) {
1611:                        TableFilter filter = (TableFilter) filters.get(j);
1612:                        String filterName = filter.getName();
1613:
1614:                        if (tableName == null || filterName.equals(tableName)) {
1615:                            Table table = filter.getTable();
1616:                            int i = table.findColumn(columnName);
1617:
1618:                            if (i != -1) {
1619:                                if (tableName == null) {
1620:                                    if (found) {
1621:                                        throw Trace
1622:                                                .error(
1623:                                                        Trace.AMBIGUOUS_COLUMN_REFERENCE,
1624:                                                        columnName);
1625:                                    }
1626:
1627:                                    //
1628:                                    found = true;
1629:                                } else {
1630:                                    return;
1631:                                }
1632:                            }
1633:                        }
1634:                    }
1635:
1636:                    if (found) {
1637:                        return;
1638:                    }
1639:
1640:                    throw Trace.error(Trace.COLUMN_NOT_FOUND, columnName);
1641:                case QUERY:
1642:
1643:                    // fredt - subquery in join condition !
1644:                    break;
1645:
1646:                case FUNCTION:
1647:                    if (function != null) {
1648:                        function.checkTables(filters);
1649:                    }
1650:                    break;
1651:
1652:                case ALL:
1653:                case ANY:
1654:                    break;
1655:
1656:                case IN:
1657:                    if (eArg2.exprType != QUERY) {
1658:                        Expression[] vl = eArg2.valueList;
1659:
1660:                        for (int i = 0; i < vl.length; i++) {
1661:                            vl[i].checkTables(filters);
1662:                        }
1663:                    }
1664:                    break;
1665:
1666:                default:
1667:                }
1668:            }
1669:
1670:            /**
1671:             * return the expression for an aliases
1672:             */
1673:            Expression getExpressionForAlias(Expression[] columns, int length) {
1674:
1675:                for (int i = 0; i < length; i++) {
1676:                    if (columnName.equals(columns[i].columnAlias)
1677:                            && (tableName == null || tableName
1678:                                    .equals(columns[i].tableName))) {
1679:                        return columns[i];
1680:                    }
1681:                }
1682:
1683:                return this ;
1684:            }
1685:
1686:            /**
1687:             * Replace aliases with expression trees
1688:             */
1689:            void replaceAliases(Expression[] columns, int length)
1690:                    throws HsqlException {
1691:
1692:                if (eArg != null) {
1693:                    if (eArg.exprType == Expression.COLUMN) {
1694:                        eArg = eArg.getExpressionForAlias(columns, length);
1695:                    } else {
1696:                        eArg.replaceAliases(columns, length);
1697:                    }
1698:                }
1699:
1700:                if (eArg2 != null) {
1701:                    if (eArg2.exprType == Expression.COLUMN) {
1702:                        eArg2 = eArg2.getExpressionForAlias(columns, length);
1703:                    } else {
1704:                        eArg2.replaceAliases(columns, length);
1705:                    }
1706:                }
1707:
1708:                switch (exprType) {
1709:
1710:                case QUERY:
1711:                    break;
1712:
1713:                case FUNCTION:
1714:                    if (function != null) {
1715:                        function.replaceAliases(columns, length);
1716:                    }
1717:                    break;
1718:
1719:                case ALL:
1720:                case ANY:
1721:                    break;
1722:
1723:                case IN:
1724:                    if (eArg2.exprType != QUERY) {
1725:                        Expression[] vl = eArg2.valueList;
1726:
1727:                        for (int i = 0; i < vl.length; i++) {
1728:                            if (vl[i].exprType == Expression.COLUMN) {
1729:                                vl[i] = vl[i].getExpressionForAlias(columns,
1730:                                        length);
1731:                            } else {
1732:                                vl[i].replaceAliases(columns, length);
1733:                            }
1734:                        }
1735:                    }
1736:                    break;
1737:
1738:                default:
1739:                }
1740:            }
1741:
1742:            /**
1743:             * Workaround for CHECK constraints. We don't want optimisation so we
1744:             * flag all LIKE expressions as already optimised.
1745:             *
1746:             * @throws HsqlException
1747:             */
1748:            void setLikeOptimised() throws HsqlException {
1749:
1750:                if (eArg != null) {
1751:                    eArg.setLikeOptimised();
1752:                }
1753:
1754:                if (eArg2 != null) {
1755:                    eArg2.setLikeOptimised();
1756:                }
1757:
1758:                if (exprType == LIKE) {
1759:                    likeObject.optimised = true;
1760:                }
1761:            }
1762:
1763:            /**
1764:             * Removes table filter resolution from an Expression tree.
1765:             */
1766:            /*
1767:             void removeFilters() throws HsqlException {
1768:
1769:             if (eArg != null) {
1770:             eArg.removeFilters();
1771:             }
1772:
1773:             if (eArg2 != null) {
1774:             eArg2.removeFilters();
1775:             }
1776:
1777:             switch (exprType) {
1778:
1779:             case COLUMN :
1780:             tableFilter = null;
1781:
1782:             return;
1783:
1784:             case QUERY :
1785:             if (subSelect != null) {
1786:             subSelect.removeFilters();
1787:             }
1788:             break;
1789:
1790:             case FUNCTION :
1791:             if (function != null) {
1792:             function.removeFilters();
1793:             }
1794:             break;
1795:
1796:             case IN :
1797:             if (eArg2.exprType != QUERY) {
1798:             Expression[] vl = eArg2.valueList;
1799:
1800:             for (int i = 0; i < vl.length; i++) {
1801:             vl[i].removeFilters();
1802:             }
1803:             }
1804:             break;
1805:
1806:             default :
1807:             }
1808:             }
1809:             */
1810:
1811:            /**
1812:             * set boolean flags and expressions for columns in a join
1813:             *
1814:             * @param filter target table filter
1815:             * @param columns boolean array
1816:             * @param elist expression list
1817:             */
1818:            void getEquiJoinColumns(TableFilter filter, boolean[] columns,
1819:                    Expression[] elist) {
1820:
1821:                if (eArg != null) {
1822:                    eArg.getEquiJoinColumns(filter, columns, elist);
1823:                }
1824:
1825:                if (eArg2 != null) {
1826:                    eArg2.getEquiJoinColumns(filter, columns, elist);
1827:                }
1828:
1829:                if (exprType == EQUAL) {
1830:                    if (eArg.tableFilter == eArg2.tableFilter) {
1831:                        return;
1832:                    }
1833:
1834:                    // an elist element may be set more than once - OK
1835:                    if (eArg.tableFilter == filter) {
1836:                        if (eArg2.exprType == COLUMN || eArg2.exprType == VALUE) {
1837:                            columns[eArg.columnIndex] = true;
1838:                            elist[eArg.columnIndex] = eArg2;
1839:                        }
1840:
1841:                        return;
1842:                    }
1843:
1844:                    if (eArg2.tableFilter == filter) {
1845:                        if (eArg.exprType == COLUMN || eArg.exprType == VALUE) {
1846:                            columns[eArg2.columnIndex] = true;
1847:                            elist[eArg2.columnIndex] = eArg;
1848:                        }
1849:                    }
1850:                }
1851:            }
1852:
1853:            /**
1854:             * Find a table filter with the given table alias
1855:             */
1856:            TableFilter findTableFilter(TableFilter[] list) {
1857:
1858:                for (int t = 0; t < list.length; t++) {
1859:                    TableFilter f = list[t];
1860:
1861:                    if (schema == null
1862:                            || f.filterTable.getSchemaName().equals(schema)) {
1863:                        if (f.getName().equals(tableName)) {
1864:                            return f;
1865:                        }
1866:                    }
1867:                }
1868:
1869:                return null;
1870:            }
1871:
1872:            /**
1873:             * Resolve the table names for columns
1874:             *
1875:             * @param f table filter
1876:             *
1877:             * @throws HsqlException
1878:             */
1879:            void resolveTables(TableFilter f) throws HsqlException {
1880:
1881:                if (isParam || f == null || exprType == Expression.VALUE) {
1882:                    return;
1883:                }
1884:
1885:                if (eArg != null) {
1886:                    eArg.resolveTables(f);
1887:                }
1888:
1889:                if (eArg2 != null) {
1890:                    eArg2.resolveTables(f);
1891:                }
1892:
1893:                switch (exprType) {
1894:
1895:                case COLUMN:
1896:                    if (tableFilter != null) {
1897:                        break;
1898:                    }
1899:
1900:                    String filterName = f.getName();
1901:
1902:                    if (tableName == null || tableName.equals(filterName)) {
1903:                        Table table = f.getTable();
1904:                        int i = table.findColumn(columnName);
1905:
1906:                        if (i != -1) {
1907:                            tableFilter = f;
1908:                            columnIndex = i;
1909:                            tableName = filterName;
1910:
1911:                            setTableColumnAttributes(table, i);
1912:
1913:                            // COLUMN is leaf; we are done
1914:                            return;
1915:                        }
1916:                    }
1917:                    break;
1918:
1919:                case QUERY:
1920:
1921:                    // we now (1_7_2_ALPHA_R) resolve independently first, then
1922:                    // resolve in the enclosing context
1923:                    if (subQuery != null) {
1924:                        subQuery.select.resolveTablesUnion(f);
1925:                    }
1926:                    break;
1927:
1928:                case FUNCTION:
1929:                    if (function != null) {
1930:                        function.resolveTables(f);
1931:                    }
1932:                    break;
1933:
1934:                case ALL:
1935:                case ANY:
1936:                    break;
1937:
1938:                case IN:
1939:                    if (eArg2.exprType != QUERY) {
1940:                        Expression[] vl = eArg2.valueList;
1941:
1942:                        for (int i = 0; i < vl.length; i++) {
1943:                            vl[i].resolveTables(f);
1944:                        }
1945:                    }
1946:                    break;
1947:
1948:                default:
1949:                }
1950:            }
1951:
1952:            /**
1953:             * For CASE WHEN and its special cases section 9.3 of the SQL standard
1954:             * on type aggregation should be implemented.
1955:             */
1956:            int getCaseWhenType(Session session) throws HsqlException {
1957:
1958:                /*
1959:                    find data type in condition
1960:                    int type = eArg.eArg.getDataType();
1961:                    then recurse on eArg2
1962:
1963:                 */
1964:                return eArg2.dataType;
1965:            }
1966:
1967:            void resolveTypes(Session session) throws HsqlException {
1968:
1969:                if (isParam) {
1970:                    return;
1971:                }
1972:
1973:                if (eArg != null) {
1974:                    eArg.resolveTypes(session);
1975:                }
1976:
1977:                if (eArg2 != null) {
1978:                    eArg2.resolveTypes(session);
1979:                }
1980:
1981:                switch (exprType) {
1982:
1983:                case VALUE:
1984:                    if (dataType == Types.BOOLEAN && valueData != null) {
1985:                        exprType = ((Boolean) valueData).booleanValue() ? TRUE
1986:                                : FALSE;
1987:                    }
1988:                    break;
1989:
1990:                case COLUMN:
1991:                    break;
1992:
1993:                case FUNCTION:
1994:                    function.resolveType(session);
1995:
1996:                    dataType = function.getReturnType();
1997:                    break;
1998:
1999:                case QUERY: {
2000:                    subQuery.select.resolveTypes(session);
2001:
2002:                    dataType = subQuery.select.exprColumns[0].dataType;
2003:
2004:                    break;
2005:                }
2006:                case NEGATE:
2007:                    if (eArg.isParam) {
2008:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2009:                                Trace.Expression_resolveTypes1);
2010:                    }
2011:
2012:                    dataType = eArg.dataType;
2013:
2014:                    if (isFixedConstant()) {
2015:                        valueData = getValue(session, dataType);
2016:                        eArg = null;
2017:                        exprType = VALUE;
2018:                    }
2019:                    break;
2020:
2021:                case ADD:
2022:
2023:                    // concat using + operator
2024:                    // non-standard concat operator to be deprecated
2025:                    if (Types.isCharacterType(eArg.dataType)
2026:                            || Types.isCharacterType(eArg2.dataType)) {
2027:                        exprType = Expression.CONCAT;
2028:                        dataType = Types.VARCHAR;
2029:
2030:                        if (isFixedConstant()) {
2031:                            valueData = getValue(session, dataType);
2032:                            eArg = null;
2033:                            eArg2 = null;
2034:                            exprType = VALUE;
2035:                        } else {
2036:                            if (eArg.isParam) {
2037:                                eArg.dataType = Types.VARCHAR;
2038:                            }
2039:
2040:                            if (eArg2.isParam) {
2041:                                eArg2.dataType = Types.VARCHAR;
2042:                            }
2043:                        }
2044:
2045:                        break;
2046:                    }
2047:                case SUBTRACT:
2048:                case MULTIPLY:
2049:                case DIVIDE:
2050:                    if (eArg.isParam && eArg2.isParam) {
2051:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2052:                                Trace.Expression_resolveTypes2);
2053:                    }
2054:
2055:                    if (isFixedConstant()) {
2056:                        dataType = Column.getCombinedNumberType(eArg.dataType,
2057:                                eArg2.dataType, exprType);
2058:                        valueData = getValue(session, dataType);
2059:                        eArg = null;
2060:                        eArg2 = null;
2061:                        exprType = VALUE;
2062:                    } else {
2063:                        if (eArg.isParam) {
2064:                            eArg.dataType = eArg2.dataType;
2065:                        } else if (eArg2.isParam) {
2066:                            eArg2.dataType = eArg.dataType;
2067:                        }
2068:
2069:                        // fredt@users 20011010 - patch 442993 by fredt
2070:                        dataType = Column.getCombinedNumberType(eArg.dataType,
2071:                                eArg2.dataType, exprType);
2072:                    }
2073:                    break;
2074:
2075:                case CONCAT:
2076:                    dataType = Types.VARCHAR;
2077:
2078:                    if (isFixedConstant()) {
2079:                        valueData = getValue(session, dataType);
2080:                        eArg = null;
2081:                        eArg2 = null;
2082:                        exprType = VALUE;
2083:                    } else {
2084:                        if (eArg.isParam) {
2085:                            eArg.dataType = Types.VARCHAR;
2086:                        }
2087:
2088:                        if (eArg2.isParam) {
2089:                            eArg2.dataType = Types.VARCHAR;
2090:                        }
2091:                    }
2092:                    break;
2093:
2094:                case EQUAL:
2095:                case BIGGER_EQUAL:
2096:                case BIGGER:
2097:                case SMALLER:
2098:                case SMALLER_EQUAL:
2099:                case NOT_EQUAL:
2100:                    if (eArg.isParam && eArg2.isParam) {
2101:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2102:                                Trace.Expression_resolveTypes3);
2103:                    }
2104:
2105:                    if (isFixedConditional()) {
2106:                        Boolean result = test(session);
2107:
2108:                        if (result == null) {
2109:                            setNull();
2110:                        } else if (result.booleanValue()) {
2111:                            exprType = TRUE;
2112:                        } else {
2113:                            exprType = FALSE;
2114:                        }
2115:
2116:                        eArg = null;
2117:                        eArg2 = null;
2118:                    } else if (eArg.isParam) {
2119:                        eArg.dataType = eArg2.dataType == Types.NULL ? Types.VARCHAR
2120:                                : eArg2.dataType;
2121:
2122:                        if (eArg2.exprType == COLUMN) {
2123:                            eArg.setTableColumnAttributes(eArg2);
2124:                        }
2125:                    } else if (eArg2.isParam) {
2126:                        eArg2.dataType = eArg.dataType == Types.NULL ? Types.VARCHAR
2127:                                : eArg.dataType;
2128:
2129:                        if (eArg.exprType == COLUMN) {
2130:                            eArg2.setTableColumnAttributes(eArg);
2131:                        }
2132:                    }
2133:
2134:                    dataType = Types.BOOLEAN;
2135:                    break;
2136:
2137:                case LIKE:
2138:                    resolveTypeForLike(session);
2139:
2140:                    dataType = Types.BOOLEAN;
2141:                    break;
2142:
2143:                case AND: {
2144:                    boolean argFixed = eArg.isFixedConditional();
2145:                    boolean arg2Fixed = eArg2.isFixedConditional();
2146:                    Boolean arg = argFixed ? (eArg.test(session)) : null;
2147:                    Boolean arg2 = arg2Fixed ? eArg2.test(session) : null;
2148:
2149:                    if (argFixed && arg2Fixed) {
2150:                        if (arg == null || arg2 == null) {
2151:                            setNull();
2152:                        } else {
2153:                            exprType = arg.booleanValue()
2154:                                    && arg2.booleanValue() ? TRUE : FALSE;
2155:                            eArg = null;
2156:                            eArg2 = null;
2157:                        }
2158:                    } else if ((argFixed && !Boolean.TRUE.equals(arg))
2159:                            || (arg2Fixed && !Boolean.TRUE.equals(arg2))) {
2160:                        exprType = FALSE;
2161:                        eArg = null;
2162:                        eArg2 = null;
2163:                    } else {
2164:                        if (eArg.isParam) {
2165:                            eArg.dataType = Types.BOOLEAN;
2166:                        }
2167:
2168:                        if (eArg2.isParam) {
2169:                            eArg2.dataType = Types.BOOLEAN;
2170:                        }
2171:                    }
2172:
2173:                    dataType = Types.BOOLEAN;
2174:
2175:                    break;
2176:                }
2177:                case OR: {
2178:                    boolean argFixed = eArg.isFixedConditional();
2179:                    boolean arg2Fixed = eArg2.isFixedConditional();
2180:                    Boolean arg = argFixed ? (eArg.test(session)) : null;
2181:                    Boolean arg2 = arg2Fixed ? eArg2.test(session) : null;
2182:
2183:                    if (argFixed && arg2Fixed) {
2184:                        if (arg == null || arg2 == null) {
2185:                            setNull();
2186:                        } else {
2187:                            exprType = arg.booleanValue()
2188:                                    || arg2.booleanValue() ? TRUE : FALSE;
2189:                            eArg = null;
2190:                            eArg2 = null;
2191:                        }
2192:                    } else if ((argFixed && Boolean.TRUE.equals(arg))
2193:                            || (arg2Fixed && Boolean.TRUE.equals(arg2))) {
2194:                        exprType = TRUE;
2195:                        eArg = null;
2196:                        eArg2 = null;
2197:                    } else {
2198:                        if (eArg.isParam) {
2199:                            eArg.dataType = Types.BOOLEAN;
2200:                        }
2201:
2202:                        if (eArg2.isParam) {
2203:                            eArg2.dataType = Types.BOOLEAN;
2204:                        }
2205:                    }
2206:
2207:                    dataType = Types.BOOLEAN;
2208:
2209:                    break;
2210:                }
2211:                case IS_NULL:
2212:                    if (isFixedConditional()) {
2213:                        exprType = Boolean.TRUE.equals(test(session)) ? TRUE
2214:                                : FALSE;
2215:                        eArg = null;
2216:                    } else if (eArg.dataType == Types.NULL) {
2217:                        eArg.dataType = Types.VARCHAR;
2218:                    }
2219:
2220:                    dataType = Types.BOOLEAN;
2221:                    break;
2222:
2223:                case NOT:
2224:                    if (isFixedConditional()) {
2225:                        Boolean arg = test(session);
2226:
2227:                        if (arg == null) {
2228:                            setNull();
2229:                        } else {
2230:                            exprType = arg.booleanValue() ? TRUE : FALSE;
2231:                            eArg = null;
2232:                        }
2233:                    } else if (eArg.isParam) {
2234:                        eArg.dataType = Types.BOOLEAN;
2235:                    }
2236:
2237:                    dataType = Types.BOOLEAN;
2238:                    break;
2239:
2240:                case ALL:
2241:                case ANY:
2242:                    dataType = eArg.dataType;
2243:                    break;
2244:
2245:                case IN:
2246:                    resolveTypeForIn(session);
2247:
2248:                    dataType = Types.BOOLEAN;
2249:                    break;
2250:
2251:                case EXISTS:
2252:
2253:                    // NOTE: no such thing as a param arg if expression is EXISTS
2254:                    // Also, cannot detect if result is fixed value
2255:                    dataType = Types.BOOLEAN;
2256:                    break;
2257:
2258:                /** @todo fredt - set the correct return type */
2259:                case COUNT:
2260:                    if (eArg.isParam) {
2261:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2262:                                Trace.Expression_resolveTypes4);
2263:                    }
2264:
2265:                    dataType = Types.INTEGER;
2266:                    break;
2267:
2268:                case MAX:
2269:                case MIN:
2270:                case SUM:
2271:                case AVG:
2272:                case EVERY:
2273:                case SOME:
2274:                case STDDEV_POP:
2275:                case STDDEV_SAMP:
2276:                case VAR_POP:
2277:                case VAR_SAMP:
2278:                    if (eArg.isParam) {
2279:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2280:                                Trace.Expression_resolveTypes4);
2281:                    }
2282:
2283:                    dataType = SetFunction.getType(exprType, eArg.dataType);
2284:                    break;
2285:
2286:                case CONVERT:
2287:
2288:                    // NOTE: both iDataType for this expr and for eArg (if isParm)
2289:                    // are already set in Parser during read
2290:                    if (eArg.isFixedConstant() || eArg.isFixedConditional()) {
2291:                        valueData = getValue(session);
2292:                        exprType = VALUE;
2293:                        eArg = null;
2294:                    }
2295:                    break;
2296:
2297:                case CASEWHEN:
2298:
2299:                    // We use CASEWHEN as parent type.
2300:                    // In the parent, eArg is the condition, and eArg2 is
2301:                    // the leaf, tagged as type ALTERNATIVE; its eArg is
2302:                    // case 1 (how to get the value when the condition in
2303:                    // the parent evaluates to true), while its eArg2 is case 2
2304:                    // (how to get the value when the condition in
2305:                    // the parent evaluates to false).
2306:                    if (eArg.isParam) {
2307:
2308:                        // condition is a paramter marker,
2309:                        // as in casewhen(?, v1, v2)
2310:                        eArg.dataType = Types.BOOLEAN;
2311:                    }
2312:
2313:                    dataType = getCaseWhenType(session);
2314:                    break;
2315:
2316:                case ALTERNATIVE: {
2317:                    Expression case1 = eArg;
2318:                    Expression case2 = eArg2;
2319:
2320:                    if (case1.isParam && case2.isParam) {
2321:                        throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2322:                                Trace.Expression_resolveTypes6);
2323:                    }
2324:
2325:                    if (case1.isParam || case1.dataType == Types.NULL) {
2326:                        case1.dataType = case2.dataType;
2327:                    } else if (case2.isParam || case2.dataType == Types.NULL) {
2328:                        case2.dataType = case1.dataType;
2329:                    }
2330:
2331:                    if (case1.dataType == Types.NULL
2332:                            && case2.dataType == Types.NULL) {
2333:                        dataType = Types.NULL;
2334:                    }
2335:
2336:                    if (Types.isNumberType(case1.dataType)
2337:                            && Types.isNumberType(case2.dataType)) {
2338:                        dataType = Column.getCombinedNumberType(case1.dataType,
2339:                                case2.dataType, ALTERNATIVE);
2340:                    } else if (Types.isCharacterType(case1.dataType)
2341:                            && Types.isCharacterType(case2.dataType)) {
2342:                        dataType = Types.LONGVARCHAR;
2343:                    } else if (case1.dataType != case2.dataType) {
2344:                        if (case2.exprType == Expression.VALUE) {
2345:                            dataType = case2.dataType = case1.dataType;
2346:                            case2.valueData = Column.convertObject(
2347:                                    case2.valueData, dataType);
2348:                        } else if (case1.exprType == Expression.VALUE) {
2349:                            dataType = case1.dataType = case2.dataType;
2350:                            case1.valueData = Column.convertObject(
2351:                                    case1.valueData, dataType);
2352:                        } else {
2353:                            throw Trace
2354:                                    .error(
2355:                                            Trace.UNRESOLVED_PARAMETER_TYPE,
2356:                                            Trace.Expression_resolveTypes7,
2357:                                            new String[] {
2358:                                                    Types
2359:                                                            .getTypeString(case1.dataType),
2360:                                                    Types
2361:                                                            .getTypeString(case2.dataType) });
2362:                        }
2363:                    } else {
2364:                        dataType = case1.dataType;
2365:                    }
2366:
2367:                    break;
2368:                }
2369:                }
2370:            }
2371:
2372:            void resolveTypeForLike(Session session) throws HsqlException {
2373:
2374:                if (eArg.isParam && eArg2.isParam) {
2375:                    throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2376:                            Trace.Expression_resolveTypeForLike);
2377:                }
2378:
2379:                if (isFixedConditional()) {
2380:                    Boolean arg = test(session);
2381:
2382:                    if (arg == null) {
2383:                        setNull();
2384:                    } else {
2385:                        exprType = arg.booleanValue() ? TRUE : FALSE;
2386:                        eArg = null;
2387:                        eArg2 = null;
2388:                    }
2389:                } else if (eArg.isParam) {
2390:                    eArg.dataType = Types.VARCHAR;
2391:                } else if (eArg2.isParam) {
2392:                    eArg2.dataType = Types.VARCHAR;
2393:                }
2394:
2395:                // boucherb@users 2003-09-25 - patch 1.7.2 Alpha P
2396:                //
2397:                // Some optimizations for LIKE
2398:                //
2399:                // TODO:
2400:                //
2401:                // See if the same optimizations can be done dynamically at execute time when
2402:                // eArg2 is PARAM.  Unfortunately, this currently requires re-resolving from
2403:                // the root any expression containing at least one parameterized LIKE in the
2404:                // compiled statement and reseting conditions on any involved table filters,
2405:                // so the answer is: probably not, at least not under the current code.
2406:                //
2407:                // CHECKME:
2408:                //
2409:                // Test for correct results under all XXXCHAR types (padding, etc.?)
2410:                //
2411:                // NOTE:
2412:                //
2413:                // For the old behaviour, simply comment out the block below
2414:                if (likeObject.optimised) {
2415:                    return;
2416:                }
2417:
2418:                boolean isRightArgFixedConstant = eArg2.isFixedConstant();
2419:                String likeStr = isRightArgFixedConstant ? (String) eArg2
2420:                        .getValue(session, Types.VARCHAR) : null;
2421:                boolean ignoreCase = eArg.dataType == Types.VARCHAR_IGNORECASE
2422:                        || eArg2.dataType == Types.VARCHAR_IGNORECASE;
2423:
2424:                likeObject.setParams(session, likeStr, ignoreCase);
2425:
2426:                if (!isRightArgFixedConstant) {
2427:
2428:                    // Then we are done here, since it's impossible
2429:                    // to determine at this point if the right expression
2430:                    // will have a fixed prefix that can be used to optimize
2431:                    // any involved table filters
2432:                    return;
2433:                }
2434:
2435:                if (likeObject.isEquivalentToFalsePredicate()) {
2436:                    exprType = FALSE;
2437:                    eArg = null;
2438:                    eArg2 = null;
2439:                    likeObject = null;
2440:                } else if (likeObject.isEquivalentToEqualsPredicate()) {
2441:                    exprType = EQUAL;
2442:                    eArg2 = new Expression(Types.VARCHAR, likeObject
2443:                            .getRangeLow());
2444:                    likeObject = null;
2445:                } else if (likeObject.isEquivalentToNotNullPredicate()) {
2446:                } else {
2447:                    if (eArg.exprType != Expression.COLUMN) {
2448:
2449:                        // Then we are done here, since range predicates are
2450:                        // not picked up for use to optimize table filters
2451:                        // unless the predicate is on the first column of
2452:                        // an index.
2453:                        // TODO:
2454:                        // We might go one step further here and check if the
2455:                        // column is elligible (is the first column of some
2456:                        // index on its table).  If it is not, it may be that
2457:                        // substituting/inserting range predicate below
2458:                        // can actually lower performance.
2459:                        // Indeed, we might better consider delaying the
2460:                        // optimizations below till the TableFilter.setConditions()
2461:                        // phase.
2462:                        return;
2463:                    }
2464:
2465:                    if (!Types.isCharacterType(eArg.dataType)) {
2466:
2467:                        // TODO:
2468:                        // correct range low / range high generation for
2469:                        // types other than XXXCHAR
2470:                        return;
2471:                    }
2472:
2473:                    boolean between = false;
2474:                    boolean like = false;
2475:                    boolean larger = false;
2476:
2477:                    if (likeObject.isEquivalentToBetweenPredicate()) {
2478:
2479:                        // X LIKE 'abc%' <=> X >= 'abc' AND X <= 'abc' || max_collation_char
2480:                        larger = likeObject.hasCollation;
2481:                        between = !larger;
2482:                        like = larger;
2483:                    } else if (likeObject
2484:                            .isEquivalentToBetweenPredicateAugmentedWithLike()) {
2485:
2486:                        // X LIKE 'abc%...' <=> X >= 'abc' AND X <= 'abc' || max_collation_char AND X LIKE 'abc%...'
2487:                        larger = likeObject.hasCollation;
2488:                        between = !larger;
2489:                        like = true;
2490:                    }
2491:
2492:                    if (between == false && larger == false) {
2493:                        return;
2494:                    }
2495:
2496:                    Expression eFirst = new Expression(Types.VARCHAR,
2497:                            likeObject.getRangeLow());
2498:                    Expression eLast = new Expression(Types.VARCHAR, likeObject
2499:                            .getRangeHigh());
2500:
2501:                    if (between && !like) {
2502:                        Expression eArgOld = eArg;
2503:
2504:                        eArg = new Expression(BIGGER_EQUAL, eArgOld, eFirst);
2505:                        eArg2 = new Expression(SMALLER_EQUAL, eArgOld, eLast);
2506:                        exprType = AND;
2507:                        likeObject = null;
2508:                    } else if (between && like) {
2509:                        Expression gte = new Expression(BIGGER_EQUAL, eArg,
2510:                                eFirst);
2511:                        Expression lte = new Expression(SMALLER_EQUAL, eArg,
2512:                                eLast);
2513:
2514:                        eArg2 = new Expression(eArg, eArg2,
2515:                                likeObject.escapeChar, likeObject.hasCollation);
2516:                        eArg2.likeObject = likeObject;
2517:                        eArg = new Expression(AND, gte, lte);
2518:                        exprType = AND;
2519:                        likeObject = null;
2520:                    } else if (larger) {
2521:                        Expression gte = new Expression(BIGGER_EQUAL, eArg,
2522:                                eFirst);
2523:
2524:                        eArg2 = new Expression(eArg, eArg2,
2525:                                likeObject.escapeChar, likeObject.hasCollation);
2526:                        eArg2.likeObject = likeObject;
2527:                        eArg = gte;
2528:                        exprType = AND;
2529:                        likeObject = null;
2530:                    }
2531:                }
2532:            }
2533:
2534:            /**
2535:             * Parametric or fixed value lists plus queries are handled.
2536:             *
2537:             * Empty lists are not allowed.
2538:             *
2539:             * Parametric predicand is resolved against the value list and vice versa.
2540:             */
2541:            void resolveTypeForIn(Session session) throws HsqlException {
2542:
2543:                if (eArg2.exprType == QUERY) {
2544:                    if (eArg.isParam) {
2545:                        eArg.dataType = eArg2.dataType;
2546:                    }
2547:
2548:                    isQueryCorrelated = !eArg2.subQuery.isResolved;
2549:                } else {
2550:                    Expression[] vl = eArg2.valueList;
2551:                    int len = vl.length;
2552:
2553:                    if (eArg.isParam) {
2554:                        if (vl[0].isParam) {
2555:                            throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
2556:                                    Trace.Expression_resolveTypeForIn2);
2557:                        }
2558:
2559:                        Expression e = vl[0];
2560:                        int dt = e.dataType;
2561:
2562:                        // PARAM datatype same as first value list expression
2563:                        // should never be Types.NULL when all is said and done
2564:                        if (dt == Types.NULL) {
2565:
2566:                            // do nothing...
2567:                        } else {
2568:                            if (eArg.dataType == Types.NULL) {
2569:                                eArg.dataType = dt;
2570:                            }
2571:
2572:                            if (eArg2.dataType == Types.NULL) {
2573:                                eArg2.dataType = dt;
2574:                            }
2575:                        }
2576:
2577:                        for (int i = 1; i < len; i++) {
2578:                            e = vl[i];
2579:
2580:                            if (e.isParam) {
2581:                                if (e.dataType == Types.NULL
2582:                                        && dt != Types.NULL) {
2583:                                    e.dataType = dt;
2584:                                }
2585:                            } else {
2586:                                e.resolveTypes(session);
2587:                            }
2588:                        }
2589:                    } else {
2590:                        int dt = eArg.dataType;
2591:
2592:                        if (eArg2.dataType == Types.NULL && dt != Types.NULL) {
2593:                            eArg2.dataType = dt;
2594:                        }
2595:
2596:                        for (int i = 0; i < len; i++) {
2597:                            Expression e = vl[i];
2598:
2599:                            if (e.isParam) {
2600:                                if (e.dataType == Types.NULL
2601:                                        && dt != Types.NULL) {
2602:                                    e.dataType = dt;
2603:                                }
2604:                            } else {
2605:                                e.resolveTypes(session);
2606:                            }
2607:                        }
2608:                    }
2609:
2610:                    eArg2.isFixedConstantValueList = eArg2.dataType != Types.VARCHAR_IGNORECASE;
2611:
2612:                    for (int i = 0; i < len; i++) {
2613:                        if (!vl[i].isFixedConstant()) {
2614:                            eArg2.isFixedConstantValueList = false;
2615:                            isQueryCorrelated = true;
2616:
2617:                            break;
2618:                        }
2619:                    }
2620:
2621:                    if (eArg2.isFixedConstantValueList) {
2622:                        eArg2.hList = new HashSet();
2623:
2624:                        for (int i = 0; i < len; i++) {
2625:                            try {
2626:                                Object value = eArg2.valueList[i]
2627:                                        .getValue(session);
2628:
2629:                                value = Column.convertObject(value,
2630:                                        eArg2.dataType);
2631:
2632:                                if (eArg2.dataType == Types.CHAR
2633:                                        && value != null) {
2634:                                    value = Library.rtrim((String) value);
2635:                                }
2636:
2637:                                eArg2.hList.add(value);
2638:                            } catch (HsqlException e) {
2639:                            }
2640:                        }
2641:                    }
2642:                }
2643:            }
2644:
2645:            /**
2646:             * Has this expression been resolved
2647:             *
2648:             *
2649:             * @return boolean
2650:             */
2651:            boolean isResolved() {
2652:
2653:                switch (exprType) {
2654:
2655:                case VALUE:
2656:                case NEGATE:
2657:                    return true;
2658:
2659:                case COLUMN:
2660:                    return tableFilter != null && tableFilter.isAssigned;
2661:
2662:                case QUERY:
2663:                    return subQuery.isResolved;
2664:                }
2665:
2666:                // todo: could recurse here, but never miss a 'false'!
2667:                return false;
2668:            }
2669:
2670:            /**
2671:             * Is the argument expression type a comparison expression
2672:             *
2673:             * @param i expresion type
2674:             *
2675:             * @return boolean
2676:             */
2677:            static boolean isCompare(int i) {
2678:
2679:                switch (i) {
2680:
2681:                case EQUAL:
2682:                case BIGGER_EQUAL:
2683:                case BIGGER:
2684:                case SMALLER:
2685:                case SMALLER_EQUAL:
2686:                case NOT_EQUAL:
2687:                    return true;
2688:                }
2689:
2690:                return false;
2691:            }
2692:
2693:            /**
2694:             * Returns the table name for a column expression as a string
2695:             *
2696:             * @return table name
2697:             */
2698:            String getTableName() {
2699:
2700:                if (exprType == ASTERISK) {
2701:                    return tableName;
2702:                }
2703:
2704:                if (exprType == COLUMN) {
2705:                    if (tableFilter == null) {
2706:                        return tableName;
2707:                    } else {
2708:                        return tableFilter.getTable().getName().name;
2709:                    }
2710:                }
2711:
2712:                // todo
2713:                return "";
2714:            }
2715:
2716:            /**
2717:             * Returns the table name for a column expression as a string
2718:             *
2719:             * @return table name
2720:             */
2721:            String getFilterTableName() {
2722:
2723:                if (tableFilter == null) {
2724:                    return "";
2725:                } else {
2726:                    return tableFilter.getTable().getName().name;
2727:                }
2728:            }
2729:
2730:            /**
2731:             * Returns the HsqlName of the table for a column expression
2732:             *
2733:             * @return table name
2734:             */
2735:            HsqlName getTableHsqlName() {
2736:
2737:                if (tableFilter == null) {
2738:                    return null;
2739:                } else {
2740:                    return tableFilter.getTable().getName();
2741:                }
2742:            }
2743:
2744:            String getTableSchemaName() {
2745:
2746:                if (tableFilter == null) {
2747:                    return null;
2748:                } else {
2749:                    return tableFilter.getTable().getName().schema.name;
2750:                }
2751:            }
2752:
2753:            /**
2754:             * Returns the name of a column as string
2755:             *
2756:             * @return column name
2757:             */
2758:            String getColumnName() {
2759:
2760:                if (exprType == COLUMN) {
2761:                    if (tableFilter == null) {
2762:                        return columnName;
2763:                    } else {
2764:                        return tableFilter.getTable().getColumn(columnIndex).columnName.name;
2765:                    }
2766:                }
2767:
2768:                return getAlias();
2769:            }
2770:
2771:            /**
2772:             * Returns the name of a column as string
2773:             *
2774:             * @return column name
2775:             */
2776:            String getBaseColumnName() {
2777:
2778:                if (exprType == COLUMN && tableFilter != null) {
2779:                    return tableFilter.getTable().getColumn(columnIndex).columnName.name;
2780:                }
2781:
2782:                return null;
2783:            }
2784:
2785:            /**
2786:             * Returns the column index in the table
2787:             *
2788:             * @return column index
2789:             */
2790:            int getColumnNr() {
2791:                return columnIndex;
2792:            }
2793:
2794:            /**
2795:             * Returns the column size
2796:             *
2797:             * @return size
2798:             */
2799:            int getColumnSize() {
2800:                return precision;
2801:            }
2802:
2803:            /**
2804:             * Returns the column scale
2805:             *
2806:             *
2807:             * @return scale
2808:             */
2809:            int getColumnScale() {
2810:                return scale;
2811:            }
2812:
2813:            /**
2814:             * Set this as a set function with / without DISTINCT
2815:             *
2816:             * @param distinct is distinct
2817:             */
2818:            void setDistinctAggregate(boolean distinct) {
2819:
2820:                isDistinctAggregate = distinct && (eArg.exprType != ASTERISK);
2821:
2822:                if (exprType == COUNT) {
2823:                    dataType = distinct ? dataType : Types.INTEGER;
2824:                }
2825:            }
2826:
2827:            /**
2828:             * Swap the condition with its complement
2829:             *
2830:             * @throws HsqlException
2831:             */
2832:            void swapCondition() throws HsqlException {
2833:
2834:                int i = EQUAL;
2835:
2836:                switch (exprType) {
2837:
2838:                case BIGGER_EQUAL:
2839:                    i = SMALLER_EQUAL;
2840:                    break;
2841:
2842:                case SMALLER_EQUAL:
2843:                    i = BIGGER_EQUAL;
2844:                    break;
2845:
2846:                case SMALLER:
2847:                    i = BIGGER;
2848:                    break;
2849:
2850:                case BIGGER:
2851:                    i = SMALLER;
2852:                    break;
2853:
2854:                case EQUAL:
2855:                    break;
2856:
2857:                default:
2858:                    Trace.doAssert(false, "Expression.swapCondition");
2859:                }
2860:
2861:                exprType = i;
2862:
2863:                Expression e = eArg;
2864:
2865:                eArg = eArg2;
2866:                eArg2 = e;
2867:            }
2868:
2869:            /**
2870:             * Returns the data type
2871:             *
2872:             *
2873:             * @return type
2874:             */
2875:            int getDataType() {
2876:                return dataType;
2877:            }
2878:
2879:            /**
2880:             * Get the value in the given type in the given session context
2881:             *
2882:             *
2883:             * @param type returned type
2884:             * @param session context
2885:             * @return value
2886:             *
2887:             * @throws HsqlException
2888:             */
2889:            Object getValue(Session session, int type) throws HsqlException {
2890:
2891:                Object o = getValue(session);
2892:
2893:                if ((o == null) || (dataType == type)) {
2894:                    return o;
2895:                }
2896:
2897:                return Column.convertObject(o, type);
2898:            }
2899:
2900:            /**
2901:             * Get the result of a SetFunction or an ordinary value
2902:             *
2903:             * @param currValue instance of set function or value
2904:             * @param session context
2905:             * @return object
2906:             *
2907:             * @throws HsqlException
2908:             */
2909:            Object getAggregatedValue(Session session, Object currValue)
2910:                    throws HsqlException {
2911:
2912:                if (!isAggregate()) {
2913:                    return currValue;
2914:                }
2915:
2916:                // handle expressions
2917:                Object leftValue = null, rightValue = null;
2918:
2919:                switch (aggregateSpec) {
2920:
2921:                case AGGREGATE_SELF: {
2922:
2923:                    // handles results of aggregates plus NEGATE and CONVERT
2924:                    switch (exprType) {
2925:
2926:                    case COUNT:
2927:                        if (currValue == null) {
2928:                            return INTEGER_0;
2929:                        }
2930:
2931:                        return ((SetFunction) currValue).getValue();
2932:
2933:                    case MAX:
2934:                    case MIN:
2935:                    case SUM:
2936:                    case AVG:
2937:                    case EVERY:
2938:                    case SOME:
2939:                    case STDDEV_POP:
2940:                    case STDDEV_SAMP:
2941:                    case VAR_POP:
2942:                    case VAR_SAMP:
2943:                        if (currValue == null) {
2944:                            return null;
2945:                        }
2946:
2947:                        return ((SetFunction) currValue).getValue();
2948:                    }
2949:                }
2950:                case AGGREGATE_LEFT:
2951:                    leftValue = eArg.getAggregatedValue(session,
2952:                            currValue == null ? null
2953:                                    : ((Object[]) currValue)[0]);
2954:
2955:                    if (currValue == null) {
2956:                        rightValue = eArg2 == null ? null : eArg2
2957:                                .getValue(session);
2958:                    } else {
2959:                        rightValue = ((Object[]) currValue)[1];
2960:                    }
2961:                    break;
2962:
2963:                case AGGREGATE_RIGHT:
2964:                    if (currValue == null) {
2965:                        leftValue = eArg == null ? null : eArg
2966:                                .getValue(session);
2967:                    } else {
2968:                        leftValue = ((Object[]) currValue)[0];
2969:                    }
2970:
2971:                    rightValue = eArg2.getAggregatedValue(session,
2972:                            currValue == null ? null
2973:                                    : ((Object[]) currValue)[1]);
2974:                    break;
2975:
2976:                case AGGREGATE_BOTH:
2977:                    if (currValue == null) {
2978:                        currValue = new Object[2];
2979:                    }
2980:
2981:                    leftValue = eArg.getAggregatedValue(session,
2982:                            ((Object[]) currValue)[0]);
2983:                    rightValue = eArg2.getAggregatedValue(session,
2984:                            ((Object[]) currValue)[1]);
2985:                    break;
2986:                }
2987:
2988:                // handle other operations
2989:                switch (exprType) {
2990:
2991:                case NEGATE:
2992:                    return Column.negate(leftValue, dataType);
2993:
2994:                case CONVERT:
2995:                    return Column.convertObject(session, leftValue, dataType,
2996:                            precision, scale);
2997:
2998:                case TRUE:
2999:                    return Boolean.TRUE;
3000:
3001:                case FALSE:
3002:                    return Boolean.FALSE;
3003:
3004:                case NOT:
3005:                    if (leftValue == null) {
3006:                        return null;
3007:                    }
3008:
3009:                    return ((Boolean) leftValue).booleanValue() ? Boolean.FALSE
3010:                            : Boolean.TRUE;
3011:
3012:                case AND:
3013:                    if (leftValue == null || rightValue == null) {
3014:                        return null;
3015:                    }
3016:
3017:                    return ((Boolean) leftValue).booleanValue()
3018:                            && ((Boolean) rightValue).booleanValue() ? Boolean.TRUE
3019:                            : Boolean.FALSE;
3020:
3021:                case OR:
3022:                    if (Boolean.TRUE.equals(leftValue)) {
3023:                        return Boolean.TRUE;
3024:                    }
3025:
3026:                    return Boolean.TRUE.equals(rightValue) ? Boolean.TRUE
3027:                            : Boolean.FALSE;
3028:
3029:                case IS_NULL:
3030:                    return leftValue == null ? Boolean.TRUE : Boolean.FALSE;
3031:
3032:                case LIKE:
3033:                    String s = (String) Column.convertObject(rightValue,
3034:                            Types.VARCHAR);
3035:
3036:                    if (eArg2.isParam || eArg2.exprType != VALUE) {
3037:                        likeObject.resetPattern(session, s);
3038:                    }
3039:
3040:                    String c = (String) Column.convertObject(leftValue,
3041:                            Types.VARCHAR);
3042:
3043:                    return likeObject.compare(session, c);
3044:
3045:                case ALL:
3046:                case ANY:
3047:                    return null;
3048:
3049:                case IN:
3050:                    return eArg2.testInCondition(session, leftValue);
3051:
3052:                case EXISTS:
3053:                    if (!eArg.subQuery.isResolved) {
3054:                        Result r = eArg.subQuery.select.getResult(session, 1); // 1 is already enough
3055:
3056:                        return r.rRoot == null ? Boolean.FALSE : Boolean.TRUE;
3057:                    } else {
3058:                        return subQuery.table.isEmpty(session) ? Boolean.FALSE
3059:                                : Boolean.TRUE;
3060:                    }
3061:                case CASEWHEN:
3062:                    leftValue = Column.convertObject(leftValue, Types.BOOLEAN);
3063:
3064:                    boolean test = ((Boolean) leftValue).booleanValue();
3065:                    Object result = test ? ((Object[]) rightValue)[0]
3066:                            : ((Object[]) rightValue)[1];
3067:
3068:                    return Column.convertObject(result, dataType);
3069:
3070:                case ALTERNATIVE:
3071:                    leftValue = Column.convertObject(leftValue, dataType);
3072:                    rightValue = Column.convertObject(rightValue, dataType);
3073:
3074:                    Object[] objectPair = new Object[2];
3075:
3076:                    objectPair[0] = leftValue;
3077:                    objectPair[1] = rightValue;
3078:
3079:                    return objectPair;
3080:
3081:                case FUNCTION:
3082:                    return function.getAggregatedValue(session, currValue);
3083:                }
3084:
3085:                // handle comparisons
3086:                if (isCompare(exprType)) {
3087:                    if (eArg2.exprType == Expression.ANY
3088:                            || eArg2.exprType == Expression.ALL) {
3089:                        return testAnyAllCondition(session, leftValue);
3090:                    }
3091:
3092:                    return compareValues(session, leftValue, rightValue);
3093:                }
3094:
3095:                // handle arithmetic and concat operations
3096:                if (leftValue != null) {
3097:                    leftValue = Column.convertObject(leftValue, dataType);
3098:                }
3099:
3100:                if (rightValue != null) {
3101:                    rightValue = Column.convertObject(rightValue, dataType);
3102:                }
3103:
3104:                switch (exprType) {
3105:
3106:                case ADD:
3107:                    return Column.add(leftValue, rightValue, dataType);
3108:
3109:                case SUBTRACT:
3110:                    return Column.subtract(leftValue, rightValue, dataType);
3111:
3112:                case MULTIPLY:
3113:                    return Column.multiply(leftValue, rightValue, dataType);
3114:
3115:                case DIVIDE:
3116:                    return Column.divide(leftValue, rightValue, dataType);
3117:
3118:                case CONCAT:
3119:                    return Column.concat(leftValue, rightValue);
3120:
3121:                default:
3122:                    throw Trace.error(Trace.NEED_AGGREGATE, this 
3123:                            .describe(session));
3124:                }
3125:            }
3126:
3127:            /**
3128:             * Instantiate the SetFunction or recurse, returning the result
3129:             *
3130:             * @param currValue setFunction
3131:             * @param session context
3132:             * @return a normal value or SetFunction instance
3133:             *
3134:             * @throws HsqlException
3135:             */
3136:            Object updateAggregatingValue(Session session, Object currValue)
3137:                    throws HsqlException {
3138:
3139:                switch (aggregateSpec) {
3140:
3141:                case AGGREGATE_SELF: {
3142:                    if (currValue == null) {
3143:                        currValue = new SetFunction(exprType, eArg.dataType,
3144:                                isDistinctAggregate);
3145:                    }
3146:
3147:                    Object newValue = eArg.exprType == ASTERISK ? INTEGER_1
3148:                            : eArg.getValue(session);
3149:
3150:                    ((SetFunction) currValue).add(session, newValue);
3151:
3152:                    return currValue;
3153:                }
3154:                case AGGREGATE_BOTH: {
3155:                    Object[] valuePair = (Object[]) currValue;
3156:
3157:                    if (valuePair == null) {
3158:                        valuePair = new Object[2];
3159:                    }
3160:
3161:                    valuePair[0] = eArg.updateAggregatingValue(session,
3162:                            valuePair[0]);
3163:                    valuePair[1] = eArg2.updateAggregatingValue(session,
3164:                            valuePair[1]);
3165:
3166:                    return valuePair;
3167:                }
3168:                case AGGREGATE_LEFT: {
3169:                    Object[] valuePair = (Object[]) currValue;
3170:
3171:                    if (valuePair == null) {
3172:                        valuePair = new Object[2];
3173:                    }
3174:
3175:                    valuePair[0] = eArg.updateAggregatingValue(session,
3176:                            valuePair[0]);
3177:
3178:                    if (eArg2 != null) {
3179:                        valuePair[1] = eArg2.getValue(session);
3180:                    }
3181:
3182:                    return valuePair;
3183:                }
3184:                case AGGREGATE_RIGHT: {
3185:                    Object[] valuePair = (Object[]) currValue;
3186:
3187:                    if (valuePair == null) {
3188:                        valuePair = new Object[2];
3189:                    }
3190:
3191:                    if (eArg != null) {
3192:                        valuePair[0] = eArg.getValue(session);
3193:                    }
3194:
3195:                    valuePair[1] = eArg2.updateAggregatingValue(session,
3196:                            valuePair[1]);
3197:
3198:                    return valuePair;
3199:                }
3200:                case AGGREGATE_FUNCTION:
3201:                    return function.updateAggregatingValue(session, currValue);
3202:
3203:                default:
3204:
3205:                    // never gets here
3206:                    return currValue;
3207:                }
3208:            }
3209:
3210:            Object getValue(Session session) throws HsqlException {
3211:
3212:                switch (exprType) {
3213:
3214:                case VALUE:
3215:                    return valueData;
3216:
3217:                case COLUMN:
3218:                    try {
3219:                        return tableFilter.currentData[columnIndex];
3220:                    } catch (NullPointerException e) {
3221:                        String name = tableName == null ? columnName
3222:                                : tableName + '.' + columnName;
3223:
3224:                        throw Trace.error(Trace.COLUMN_NOT_FOUND, name);
3225:                    }
3226:                case FUNCTION:
3227:                    return function.getValue(session);
3228:
3229:                case QUERY:
3230:                    return subQuery.select.getValue(session, dataType);
3231:
3232:                case NEGATE:
3233:                    return Column.negate(eArg.getValue(session, dataType),
3234:                            dataType);
3235:
3236:                case ALL:
3237:                case ANY:
3238:                    return null;
3239:
3240:                case AND:
3241:                case OR:
3242:                case LIKE:
3243:                case EXISTS:
3244:                case IN:
3245:                    return test(session);
3246:
3247:                case CONVERT:
3248:                    return Column.convertObject(session,
3249:                            eArg.getValue(session), dataType, precision, scale);
3250:
3251:                case CASEWHEN:
3252:                    Boolean result = eArg.test(session);
3253:
3254:                    if (Boolean.TRUE.equals(result)) {
3255:                        return eArg2.eArg.getValue(session, dataType);
3256:                    } else {
3257:                        return eArg2.eArg2.getValue(session, dataType);
3258:                    }
3259:
3260:                    // gets here from getAggregatedValue()
3261:                case ALTERNATIVE:
3262:                    return new Object[] { eArg.getValue(session, dataType),
3263:                            eArg2.getValue(session, dataType) };
3264:                }
3265:
3266:                // todo: simplify this
3267:                Object a = null, b = null;
3268:
3269:                if (eArg != null) {
3270:                    a = eArg.getValue(session, dataType);
3271:                }
3272:
3273:                if (eArg2 != null) {
3274:                    b = eArg2.getValue(session, dataType);
3275:                }
3276:
3277:                switch (exprType) {
3278:
3279:                case ADD:
3280:                    return Column.add(a, b, dataType);
3281:
3282:                case SUBTRACT:
3283:                    return Column.subtract(a, b, dataType);
3284:
3285:                case MULTIPLY:
3286:                    return Column.multiply(a, b, dataType);
3287:
3288:                case DIVIDE:
3289:                    return Column.divide(a, b, dataType);
3290:
3291:                case CONCAT:
3292:                    return Column.concat(a, b);
3293:
3294:                case SEQUENCE:
3295:                    return ((NumberSequence) valueData).getValueObject();
3296:
3297:                default:
3298:
3299:                    /** @todo fredt - make sure the expression type is always comparison here */
3300:                    return test(session);
3301:                }
3302:            }
3303:
3304:            boolean testCondition(Session session) throws HsqlException {
3305:                return Boolean.TRUE.equals(test(session));
3306:            }
3307:
3308:            /**
3309:             * Returns the test result of a conditional expression
3310:             *
3311:             * @param session session
3312:             * @return boolean
3313:             * @throws HsqlException
3314:             */
3315:            Boolean test(Session session) throws HsqlException {
3316:
3317:                switch (exprType) {
3318:
3319:                case TRUE:
3320:                    return Boolean.TRUE;
3321:
3322:                case FALSE:
3323:                    return Boolean.FALSE;
3324:
3325:                case NOT:
3326:                    if (eArg2 != null) {
3327:                        Trace.doAssert(false, "Expression.test");
3328:                    }
3329:
3330:                    Boolean result = eArg.test(session);
3331:
3332:                    return result == null ? null
3333:                            : result.booleanValue() ? Boolean.FALSE
3334:                                    : Boolean.TRUE;
3335:
3336:                case AND: {
3337:                    Boolean r1 = eArg.test(session);
3338:
3339:                    if (r1 == null) {
3340:                        return null;
3341:                    }
3342:
3343:                    Boolean r2 = eArg2.test(session);
3344:
3345:                    if (r2 == null) {
3346:                        return null;
3347:                    }
3348:
3349:                    return r1.booleanValue() && r2.booleanValue() ? Boolean.TRUE
3350:                            : Boolean.FALSE;
3351:                }
3352:                case OR: {
3353:                    boolean r1 = Boolean.TRUE.equals(eArg.test(session));
3354:
3355:                    if (r1) {
3356:                        return Boolean.TRUE;
3357:                    }
3358:
3359:                    return Boolean.TRUE.equals(eArg2.test(session)) ? Boolean.TRUE
3360:                            : Boolean.FALSE;
3361:                }
3362:                case IS_NULL:
3363:                    return eArg.getValue(session) == null ? Boolean.TRUE
3364:                            : Boolean.FALSE;
3365:
3366:                case LIKE:
3367:                    String s = (String) eArg2.getValue(session, Types.VARCHAR);
3368:
3369:                    if (eArg2.isParam || eArg2.exprType != VALUE) {
3370:                        likeObject.resetPattern(session, s);
3371:                    }
3372:
3373:                    String c = (String) eArg.getValue(session, Types.VARCHAR);
3374:
3375:                    return likeObject.compare(session, c);
3376:
3377:                case IN:
3378:                    return eArg2.testInCondition(session, eArg
3379:                            .getValue(session));
3380:
3381:                case EXISTS:
3382:                    return eArg.testExistsCondition(session);
3383:
3384:                case FUNCTION:
3385:                    Object value = Column.convertObject(function
3386:                            .getValue(session), Types.BOOLEAN);
3387:
3388:                    return (Boolean) value;
3389:                }
3390:
3391:                if (eArg == null || eArg2 == null) {
3392:                    if (exprType == COLUMN) {
3393:                        if (dataType == Types.BOOLEAN
3394:                                || Types.isNumberType(dataType)) {
3395:                            Object value = Column.convertObject(
3396:                                    getValue(session), Types.BOOLEAN);
3397:
3398:                            return (Boolean) value;
3399:                        }
3400:                    }
3401:
3402:                    throw Trace.error(Trace.NOT_A_CONDITION);
3403:                }
3404:
3405:                if (eArg2.exprType == Expression.ANY
3406:                        || eArg2.exprType == Expression.ALL) {
3407:                    return testAnyAllCondition(session, eArg.getValue(session));
3408:                }
3409:
3410:                Object o1 = eArg.getValue(session);
3411:                Object o2 = eArg2.getValue(session);
3412:
3413:                if (o1 == null || o2 == null) {
3414:                    /*
3415:                     TableFilter.swapCondition() ensures that with LEFT OUTER, eArg is the
3416:                     column expression for the table on the right hand side.
3417:                     We do not join tables on nulls apart from outer joins
3418:                     Any comparison operator can exist in WHERE or JOIN conditions
3419:                     */
3420:                    if (eArg.tableFilter != null
3421:                            && eArg.tableFilter.isOuterJoin) {
3422:                        if (isInJoin) {
3423:                            if (eArg.tableFilter.isCurrentOuter && o1 == null) {
3424:                                return Boolean.TRUE;
3425:                            }
3426:                        } else {
3427:
3428:                            // this is used in WHERE <OUTER JOIN COL> IS [NOT] NULL
3429:                            eArg.tableFilter.nonJoinIsNull = o2 == null;
3430:                        }
3431:                    }
3432:
3433:                    return null;
3434:                }
3435:
3436:                return compareValues(session, o1, o2);
3437:            }
3438:
3439:            private Boolean compareValues(Session session, Object o1, Object o2)
3440:                    throws HsqlException {
3441:
3442:                int type = eArg.dataType;
3443:
3444:                if (eArg.dataType != eArg2.dataType) {
3445:                    if (Types.isNumberType(eArg.dataType)
3446:                            && Types.isNumberType(eArg2.dataType)) {
3447:                        type = Column.getCombinedNumberType(eArg.dataType,
3448:                                eArg2.dataType, exprType);
3449:                    }
3450:
3451:                    o1 = Column.convertObject(o1, type);
3452:                    o2 = Column.convertObject(o2, type);
3453:                }
3454:
3455:                int result = Column.compare(session.database.collation, o1, o2,
3456:                        type);
3457:
3458:                switch (exprType) {
3459:
3460:                case EQUAL:
3461:                    return result == 0 ? Boolean.TRUE : Boolean.FALSE;
3462:
3463:                case BIGGER:
3464:                    return result > 0 ? Boolean.TRUE : Boolean.FALSE;
3465:
3466:                case BIGGER_EQUAL:
3467:                    return result >= 0 ? Boolean.TRUE : Boolean.FALSE;
3468:
3469:                case SMALLER_EQUAL:
3470:                    return result <= 0 ? Boolean.TRUE : Boolean.FALSE;
3471:
3472:                case SMALLER:
3473:                    return result < 0 ? Boolean.TRUE : Boolean.FALSE;
3474:
3475:                case NOT_EQUAL:
3476:                    return result != 0 ? Boolean.TRUE : Boolean.FALSE;
3477:
3478:                default:
3479:                    throw Trace.error(Trace.GENERAL_ERROR,
3480:                            Trace.Expression_compareValues);
3481:                }
3482:            }
3483:
3484:            /**
3485:             * Returns the result of testing a VALUE_LIST expression
3486:             *
3487:             * @param o value to check against
3488:             * @param session context
3489:             * @return boolean
3490:             * @throws HsqlException
3491:             */
3492:            private Boolean testInCondition(Session session, Object o)
3493:                    throws HsqlException {
3494:
3495:                if (o == null) {
3496:                    return null;
3497:                }
3498:
3499:                if (exprType == VALUELIST) {
3500:                    try {
3501:                        o = Column.convertObject(o, dataType);
3502:                    } catch (HsqlException e) {
3503:                        return Boolean.FALSE;
3504:                    }
3505:
3506:                    if (isFixedConstantValueList) {
3507:                        if (dataType == Types.CHAR) {
3508:                            o = Library.rtrim((String) o);
3509:                        }
3510:
3511:                        return hList.contains(o) ? Boolean.TRUE : Boolean.FALSE;
3512:                    }
3513:
3514:                    final int len = valueList.length;
3515:
3516:                    for (int i = 0; i < len; i++) {
3517:                        Object o2 = valueList[i].getValue(session, dataType);
3518:
3519:                        if (Column.compare(session.database.collation, o, o2,
3520:                                dataType) == 0) {
3521:                            return Boolean.TRUE;
3522:                        }
3523:                    }
3524:
3525:                    return Boolean.FALSE;
3526:                } else if (exprType == QUERY) {
3527:
3528:                    /** @todo fredt - convert to join */
3529:                    try {
3530:                        o = Column.convertObject(o, subQuery.table
3531:                                .getColumnTypes()[0]);
3532:                    } catch (HsqlException e) {
3533:                        return Boolean.FALSE;
3534:                    }
3535:
3536:                    if (!subQuery.isResolved) {
3537:                        subQuery.populateTable(session);
3538:                    }
3539:
3540:                    Boolean result = subQuery.table.getPrimaryIndex()
3541:                            .findFirstRow(session, o, Expression.EQUAL)
3542:                            .hasNext() ? Boolean.TRUE : Boolean.FALSE;
3543:
3544:                    if (!subQuery.isResolved) {
3545:                        subQuery.table.clearAllRows(session);
3546:                    }
3547:
3548:                    return result;
3549:                }
3550:
3551:                throw Trace.error(Trace.WRONG_DATA_TYPE);
3552:            }
3553:
3554:            private Boolean testExistsCondition(Session session)
3555:                    throws HsqlException {
3556:
3557:                if (subQuery.isResolved) {
3558:                    return subQuery.table.isEmpty(session) ? Boolean.FALSE
3559:                            : Boolean.TRUE;
3560:                } else {
3561:                    Result r = subQuery.select.getResult(session, 1); // 1 is already enough
3562:
3563:                    return r.rRoot == null ? Boolean.FALSE : Boolean.TRUE;
3564:                }
3565:            }
3566:
3567:            private Boolean testAnyAllCondition(Session session, Object o)
3568:                    throws HsqlException {
3569:
3570:                if (o == null) {
3571:                    return null;
3572:                }
3573:
3574:                SubQuery subquery = eArg2.eArg.subQuery;
3575:                boolean populate = !subquery.isResolved;
3576:
3577:                if (populate) {
3578:                    subquery.populateTable(session);
3579:                }
3580:
3581:                Boolean result = getAnyAllValue(session, o, subquery);
3582:
3583:                if (populate) {
3584:                    subquery.table.clearAllRows(session);
3585:                }
3586:
3587:                return result;
3588:            }
3589:
3590:            private Boolean getAnyAllValue(Session session, Object o,
3591:                    SubQuery subquery) throws HsqlException {
3592:
3593:                boolean empty = subquery.table.isEmpty(session);
3594:                Index index = subquery.table.getPrimaryIndex();
3595:                RowIterator it = index.findFirstRowNotNull(session);
3596:                Row firstrow = it.next();
3597:
3598:                switch (eArg2.exprType) {
3599:
3600:                case ANY: {
3601:                    if (empty) {
3602:                        return Boolean.FALSE;
3603:                    }
3604:
3605:                    if (firstrow == null) {
3606:                        return null;
3607:                    }
3608:
3609:                    int range = Column.compareToTypeRange(o, eArg2.eArg
3610:                            .getDataType());
3611:
3612:                    if (range != 0) {
3613:                        switch (exprType) {
3614:
3615:                        case EQUAL:
3616:                            return Boolean.FALSE;
3617:
3618:                        case NOT_EQUAL:
3619:                            return Boolean.TRUE;
3620:
3621:                        case BIGGER:
3622:                        case BIGGER_EQUAL:
3623:                            return range > 0 ? Boolean.TRUE : Boolean.FALSE;
3624:
3625:                        case SMALLER_EQUAL:
3626:                        case SMALLER:
3627:                            return range < 0 ? Boolean.TRUE : Boolean.FALSE;
3628:                        }
3629:                    }
3630:
3631:                    o = Column.convertObject(o, eArg2.eArg.getDataType());
3632:
3633:                    if (exprType == EQUAL) {
3634:                        it = index.findFirstRow(session, o, EQUAL);
3635:
3636:                        return it.hasNext() ? Boolean.TRUE : Boolean.FALSE;
3637:                    }
3638:
3639:                    Row lastrow = index.lastRow(session);
3640:                    Object firstdata = firstrow.getData()[0];
3641:                    Object lastdata = lastrow.getData()[0];
3642:                    int comparefirst = Column.compare(
3643:                            session.database.collation, o, firstdata, eArg
3644:                                    .getDataType());
3645:                    int comparelast = Column.compare(
3646:                            session.database.collation, o, lastdata, eArg
3647:                                    .getDataType());
3648:
3649:                    switch (exprType) {
3650:
3651:                    case NOT_EQUAL:
3652:                        return (comparefirst == 0 && comparelast == 0) ? Boolean.FALSE
3653:                                : Boolean.TRUE;
3654:
3655:                    case BIGGER:
3656:                        return comparefirst > 0 ? Boolean.TRUE : Boolean.FALSE;
3657:
3658:                    case BIGGER_EQUAL:
3659:                        return comparefirst >= 0 ? Boolean.TRUE : Boolean.FALSE;
3660:
3661:                    case SMALLER:
3662:                        return comparelast < 0 ? Boolean.TRUE : Boolean.FALSE;
3663:
3664:                    case SMALLER_EQUAL:
3665:                        return comparelast <= 0 ? Boolean.TRUE : Boolean.FALSE;
3666:                    }
3667:
3668:                    break;
3669:                }
3670:                case ALL: {
3671:                    if (empty) {
3672:                        return Boolean.TRUE;
3673:                    }
3674:
3675:                    if (firstrow == null) {
3676:                        return null;
3677:                    }
3678:
3679:                    int range = Column.compareToTypeRange(o, eArg2.eArg
3680:                            .getDataType());
3681:
3682:                    if (range != 0) {
3683:                        switch (exprType) {
3684:
3685:                        case EQUAL:
3686:                            return Boolean.FALSE;
3687:
3688:                        case NOT_EQUAL:
3689:                            return Boolean.TRUE;
3690:
3691:                        case BIGGER:
3692:                        case BIGGER_EQUAL:
3693:                            return range > 0 ? Boolean.TRUE : Boolean.FALSE;
3694:
3695:                        case SMALLER_EQUAL:
3696:                        case SMALLER:
3697:                            return range < 0 ? Boolean.TRUE : Boolean.FALSE;
3698:                        }
3699:                    }
3700:
3701:                    o = Column.convertObject(o, eArg2.eArg.getDataType());
3702:
3703:                    if (exprType == EQUAL || exprType == NOT_EQUAL) {
3704:                        it = index.findFirstRow(session, o, EQUAL);
3705:
3706:                        if (exprType == EQUAL) {
3707:                            return (it.hasNext() && subquery.table
3708:                                    .getRowCount(session) == 1) ? Boolean.TRUE
3709:                                    : Boolean.FALSE;
3710:                        }
3711:
3712:                        return (it.hasNext()) ? Boolean.FALSE : Boolean.TRUE;
3713:                    }
3714:
3715:                    Row lastrow = index.lastRow(session);
3716:                    Object firstdata = firstrow.getData()[0];
3717:                    Object lastdata = lastrow.getData()[0];
3718:
3719:                    o = Column.convertObject(o, eArg2.eArg.getDataType());
3720:
3721:                    int comparefirst = Column.compare(
3722:                            session.database.collation, o, firstdata, eArg
3723:                                    .getDataType());
3724:                    int comparelast = Column.compare(
3725:                            session.database.collation, o, lastdata, eArg
3726:                                    .getDataType());
3727:
3728:                    switch (exprType) {
3729:
3730:                    case NOT_EQUAL:
3731:                        return (comparefirst == 0 || comparelast == 0) ? Boolean.FALSE
3732:                                : Boolean.TRUE;
3733:
3734:                    case BIGGER:
3735:                        return comparelast > 0 ? Boolean.TRUE : Boolean.FALSE;
3736:
3737:                    case BIGGER_EQUAL:
3738:                        return comparelast >= 0 ? Boolean.TRUE : Boolean.FALSE;
3739:
3740:                    case SMALLER:
3741:                        return comparefirst < 0 ? Boolean.TRUE : Boolean.FALSE;
3742:
3743:                    case SMALLER_EQUAL:
3744:                        return comparefirst <= 0 ? Boolean.TRUE : Boolean.FALSE;
3745:                    }
3746:
3747:                    break;
3748:                }
3749:                }
3750:
3751:                return null;
3752:            }
3753:
3754:            /**
3755:             * Marks all the expressions in the tree for a condition that is part
3756:             * of a JOIN .. ON ....<br>
3757:             *
3758:             * For LEFT OUTER joins, also tests the expression tree for the join
3759:             * condition to ensure only permitted expression types are there.
3760:             *
3761:             * If we want to exapand the expressions to include arithmetic operations
3762:             * or functions ...
3763:             *
3764:             * (fredt@users)
3765:             *
3766:             * @param tf table filter
3767:             * @param outer boolean
3768:             * @return boolean
3769:             */
3770:            boolean setForJoin(TableFilter tf, boolean outer) {
3771:
3772:                isInJoin = outer;
3773:
3774:                if (outer) {
3775:                    outerFilter = tf;
3776:                }
3777:
3778:                if (eArg != null) {
3779:                    if (eArg.setForJoin(tf, outer) == false) {
3780:                        return false;
3781:                    }
3782:                }
3783:
3784:                if (eArg2 != null) {
3785:                    if (eArg2.setForJoin(tf, outer) == false) {
3786:                        return false;
3787:                    }
3788:                }
3789:
3790:                return !outer
3791:                        || (exprType == Expression.AND
3792:                                || exprType == Expression.OR
3793:                                || exprType == Expression.COLUMN
3794:                                || exprType == Expression.VALUE
3795:                                || exprType == Expression.EQUAL
3796:                                || exprType == Expression.NOT_EQUAL
3797:                                || exprType == Expression.BIGGER
3798:                                || exprType == Expression.BIGGER_EQUAL
3799:                                || exprType == Expression.SMALLER
3800:                                || exprType == Expression.SMALLER_EQUAL || exprType == Expression.IS_NULL);
3801:            }
3802:
3803:            /**
3804:             * Returns a Select object that can be used for checking the contents
3805:             * of an existing table against the given CHECK search condition.
3806:             *
3807:             * @param t table
3808:             * @param e expression
3809:             * @return select object
3810:             * @throws HsqlException
3811:             */
3812:            static Select getCheckSelect(Session session, Table t, Expression e)
3813:                    throws HsqlException {
3814:
3815:                Select s = new Select();
3816:
3817:                s.exprColumns = new Expression[1];
3818:                s.exprColumns[0] = new Expression(VALUE, Boolean.TRUE);
3819:                s.tFilter = new TableFilter[1];
3820:                s.tFilter[0] = new TableFilter(t, null, null, false);
3821:
3822:                Expression condition = new Expression(NOT, e, null);
3823:
3824:                s.queryCondition = condition;
3825:
3826:                s.resolveAll(session, true);
3827:
3828:                return s;
3829:            }
3830:
3831:            /**
3832:             * Sets the left leaf.
3833:             *
3834:             * @param e expression
3835:             */
3836:            void setLeftExpression(Expression e) {
3837:                eArg = e;
3838:            }
3839:
3840:            void setRightExpression(Expression e) {
3841:                eArg2 = e;
3842:            }
3843:
3844:            /**
3845:             * Gets the right leaf.
3846:             *
3847:             * @return expression
3848:             */
3849:            Expression getRightExpression() {
3850:                return eArg2;
3851:            }
3852:
3853:            // boucherb@users 20030417 - patch 1.7.2 - compiled statement support
3854:            void bind(Object o) {
3855:                valueData = o;
3856:            }
3857:
3858:            boolean isParam() {
3859:                return isParam;
3860:            }
3861:
3862:            boolean isFixedConstant() {
3863:
3864:                switch (exprType) {
3865:
3866:                case VALUE:
3867:                    return !isParam;
3868:
3869:                case NEGATE:
3870:                    return eArg.isFixedConstant();
3871:
3872:                case ADD:
3873:                case SUBTRACT:
3874:                case MULTIPLY:
3875:                case DIVIDE:
3876:                case CONCAT:
3877:                    return eArg.isFixedConstant() && eArg2.isFixedConstant();
3878:                }
3879:
3880:                return false;
3881:            }
3882:
3883:            boolean isFixedConditional() {
3884:
3885:                switch (exprType) {
3886:
3887:                case TRUE:
3888:                case FALSE:
3889:                    return true;
3890:
3891:                case EQUAL:
3892:                case BIGGER_EQUAL:
3893:                case BIGGER:
3894:                case SMALLER:
3895:                case SMALLER_EQUAL:
3896:                case NOT_EQUAL:
3897:                case LIKE:
3898:
3899:                    //case IN : TODO
3900:                    return eArg.isFixedConstant() && eArg2.isFixedConstant();
3901:
3902:                case IS_NULL:
3903:                    return eArg.isFixedConstant();
3904:
3905:                case NOT:
3906:                    return eArg.isFixedConditional();
3907:
3908:                case AND:
3909:                case OR:
3910:                    return eArg.isFixedConditional()
3911:                            && eArg2.isFixedConditional();
3912:
3913:                default:
3914:                    return false;
3915:                }
3916:            }
3917:
3918:            void setTableColumnAttributes(Expression e) {
3919:
3920:                precision = e.precision;
3921:                scale = e.scale;
3922:                isIdentity = e.isIdentity;
3923:                nullability = e.nullability;
3924:                isWritable = e.isWritable;
3925:                catalog = e.catalog;
3926:                schema = e.schema;
3927:            }
3928:
3929:            void setTableColumnAttributes(Table t, int i) {
3930:
3931:                Column c = t.getColumn(i);
3932:
3933:                dataType = c.getType();
3934:                precision = c.getSize();
3935:                scale = c.getScale();
3936:                isIdentity = c.isIdentity();
3937:
3938:                // IDENTITY columns are not nullable but NULLs are accepted
3939:                // and converted into the next identity value for the table
3940:                nullability = c.isNullable() && !isIdentity ? NULLABLE
3941:                        : NO_NULLS;
3942:                isWritable = t.isWritable();
3943:                catalog = t.getCatalogName();
3944:                schema = t.getSchemaName();
3945:            }
3946:
3947:            String getValueClassName() {
3948:
3949:                // boucherb@users 20050516 - patch 1.8.0 removed DITypeInfo dependency
3950:                if (valueClassName == null) {
3951:                    if (function == null) {
3952:                        valueClassName = Types
3953:                                .getColStClsName((dataType == Types.VARCHAR_IGNORECASE) ? Types.VARCHAR
3954:                                        : dataType);
3955:                    } else {
3956:                        valueClassName = function.getReturnClassName();
3957:                    }
3958:                }
3959:
3960:                return valueClassName;
3961:            }
3962:
3963:            // parameter modes
3964:            static final int PARAM_UNKNOWN = 0;
3965:            public static final int PARAM_IN = 1;
3966:            public static final int PARAM_IN_OUT = 2;
3967:            public static final int PARAM_OUT = 4;
3968:
3969:            // result set (output column value) or parameter expression nullability
3970:            static final int NO_NULLS = 0;
3971:            static final int NULLABLE = 1;
3972:            static final int NULLABLE_UNKNOWN = 2;
3973:
3974:            // output column and parameter expression metadata values
3975:            boolean isIdentity; // = false
3976:            int nullability = NULLABLE_UNKNOWN;
3977:            boolean isWritable; // = false; true if column of writable table
3978:            int paramMode = PARAM_UNKNOWN;
3979:            String valueClassName; // = null
3980:
3981:            // boucherb@users 20040111 - patch 1.7.2 RC1 - metadata xxxusage support
3982:            //-------------------------------------------------------------------
3983:            // TODO:  Maybe provide an interface or abstract class + a default
3984:            // implementation instead?  This would allow a more powerful system
3985:            // of collectors to be created, for example to assist in the optimization
3986:            // of condition expression trees:
3987:            //
3988:            // HashSet joins = new JoinConditionCollector();
3989:            // joins.addAll(select.whereCondition);
3990:            // for(Iterator it = joins.iterator(); it.hasNext();) {
3991:            //      process((it.next());
3992:            // }
3993:
3994:            /**
3995:             * Provides a generic way to collect a set of distinct expressions
3996:             * of some type from a tree rooted at a specified Expression.
3997:             */
3998:            static class Collector extends HashSet {
3999:
4000:                Collector() {
4001:                    super ();
4002:                }
4003:
4004:                void addAll(Expression e, int type) {
4005:
4006:                    Function function;
4007:                    Expression[] list;
4008:
4009:                    if (e == null) {
4010:                        return;
4011:                    }
4012:
4013:                    addAll(e.getArg(), type);
4014:                    addAll(e.getArg2(), type);
4015:
4016:                    // CHECKME: What about setTrue() Expressions?
4017:                    if (e.exprType == type) {
4018:                        add(e);
4019:                    }
4020:
4021:                    if (e.subQuery != null) {
4022:                        addAll(e.subQuery.select, type);
4023:                    }
4024:
4025:                    function = e.function;
4026:
4027:                    if (function != null) {
4028:                        list = function.eArg;
4029:
4030:                        if (list != null) {
4031:                            for (int i = 0; i < list.length; i++) {
4032:                                addAll(list[i], type);
4033:                            }
4034:                        }
4035:                    }
4036:
4037:                    list = e.valueList;
4038:
4039:                    if (list != null) {
4040:                        for (int i = 0; i < list.length; i++) {
4041:                            addAll(list[i], type);
4042:                        }
4043:                    }
4044:                }
4045:
4046:                void addAll(Select select, int type) {
4047:
4048:                    for (; select != null; select = select.unionSelect) {
4049:                        Expression[] list = select.exprColumns;
4050:
4051:                        for (int i = 0; i < list.length; i++) {
4052:                            addAll(list[i], type);
4053:                        }
4054:
4055:                        addAll(select.queryCondition, type);
4056:                        addAll(select.havingCondition, type);
4057:
4058:                        // todo order by columns
4059:                    }
4060:                }
4061:            }
4062:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.