Source Code Cross Referenced for Parser.java in  » Database-DBMS » h2database » org » h2 » command » 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 » h2database » org.h2.command 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
0003:         * (http://h2database.com/html/license.html).
0004:         * Initial Developer: H2 Group
0005:         */
0006:        package org.h2.command;
0007:
0008:        import java.math.BigDecimal;
0009:        import java.math.BigInteger;
0010:        import java.sql.SQLException;
0011:        import java.text.Collator;
0012:        import java.util.HashSet;
0013:
0014:        import org.h2.api.Trigger;
0015:        import org.h2.command.ddl.AlterIndexRename;
0016:        import org.h2.command.ddl.AlterTableAddConstraint;
0017:        import org.h2.command.ddl.AlterTableAlterColumn;
0018:        import org.h2.command.ddl.AlterTableDropConstraint;
0019:        import org.h2.command.ddl.AlterTableRename;
0020:        import org.h2.command.ddl.AlterTableRenameColumn;
0021:        import org.h2.command.ddl.AlterUser;
0022:        import org.h2.command.ddl.AlterView;
0023:        import org.h2.command.ddl.Analyze;
0024:        import org.h2.command.ddl.CreateAggregate;
0025:        import org.h2.command.ddl.CreateConstant;
0026:        import org.h2.command.ddl.CreateFunctionAlias;
0027:        import org.h2.command.ddl.CreateIndex;
0028:        import org.h2.command.ddl.CreateLinkedTable;
0029:        import org.h2.command.ddl.CreateRole;
0030:        import org.h2.command.ddl.CreateSchema;
0031:        import org.h2.command.ddl.CreateSequence;
0032:        import org.h2.command.ddl.CreateTable;
0033:        import org.h2.command.ddl.CreateTrigger;
0034:        import org.h2.command.ddl.CreateUser;
0035:        import org.h2.command.ddl.CreateUserDataType;
0036:        import org.h2.command.ddl.CreateView;
0037:        import org.h2.command.ddl.DeallocateProcedure;
0038:        import org.h2.command.ddl.DropAggregate;
0039:        import org.h2.command.ddl.DropConstant;
0040:        import org.h2.command.ddl.DropDatabase;
0041:        import org.h2.command.ddl.DropFunctionAlias;
0042:        import org.h2.command.ddl.DropIndex;
0043:        import org.h2.command.ddl.DropRole;
0044:        import org.h2.command.ddl.DropSchema;
0045:        import org.h2.command.ddl.DropSequence;
0046:        import org.h2.command.ddl.DropTable;
0047:        import org.h2.command.ddl.DropTrigger;
0048:        import org.h2.command.ddl.DropUser;
0049:        import org.h2.command.ddl.DropUserDataType;
0050:        import org.h2.command.ddl.DropView;
0051:        import org.h2.command.ddl.GrantRevoke;
0052:        import org.h2.command.ddl.PrepareProcedure;
0053:        import org.h2.command.ddl.SetComment;
0054:        import org.h2.command.ddl.TruncateTable;
0055:        import org.h2.command.dml.AlterSequence;
0056:        import org.h2.command.dml.AlterTableSet;
0057:        import org.h2.command.dml.BackupCommand;
0058:        import org.h2.command.dml.Call;
0059:        import org.h2.command.dml.Delete;
0060:        import org.h2.command.dml.ExecuteProcedure;
0061:        import org.h2.command.dml.ExplainPlan;
0062:        import org.h2.command.dml.Insert;
0063:        import org.h2.command.dml.Merge;
0064:        import org.h2.command.dml.NoOperation;
0065:        import org.h2.command.dml.Query;
0066:        import org.h2.command.dml.RunScriptCommand;
0067:        import org.h2.command.dml.ScriptCommand;
0068:        import org.h2.command.dml.Select;
0069:        import org.h2.command.dml.SelectOrderBy;
0070:        import org.h2.command.dml.SelectUnion;
0071:        import org.h2.command.dml.Set;
0072:        import org.h2.command.dml.SetTypes;
0073:        import org.h2.command.dml.TransactionCommand;
0074:        import org.h2.command.dml.Update;
0075:        import org.h2.constant.ErrorCode;
0076:        import org.h2.constant.SysProperties;
0077:        import org.h2.constraint.ConstraintReferential;
0078:        import org.h2.engine.Constants;
0079:        import org.h2.engine.Database;
0080:        import org.h2.engine.DbObject;
0081:        import org.h2.engine.FunctionAlias;
0082:        import org.h2.engine.Procedure;
0083:        import org.h2.engine.Right;
0084:        import org.h2.engine.Session;
0085:        import org.h2.engine.Setting;
0086:        import org.h2.engine.User;
0087:        import org.h2.engine.UserAggregate;
0088:        import org.h2.engine.UserDataType;
0089:        import org.h2.expression.Aggregate;
0090:        import org.h2.expression.Alias;
0091:        import org.h2.expression.CompareLike;
0092:        import org.h2.expression.Comparison;
0093:        import org.h2.expression.ConditionAndOr;
0094:        import org.h2.expression.ConditionExists;
0095:        import org.h2.expression.ConditionIn;
0096:        import org.h2.expression.ConditionInSelect;
0097:        import org.h2.expression.ConditionNot;
0098:        import org.h2.expression.Expression;
0099:        import org.h2.expression.ExpressionColumn;
0100:        import org.h2.expression.ExpressionList;
0101:        import org.h2.expression.Function;
0102:        import org.h2.expression.FunctionCall;
0103:        import org.h2.expression.JavaAggregate;
0104:        import org.h2.expression.JavaFunction;
0105:        import org.h2.expression.Operation;
0106:        import org.h2.expression.Parameter;
0107:        import org.h2.expression.Rownum;
0108:        import org.h2.expression.SequenceValue;
0109:        import org.h2.expression.Subquery;
0110:        import org.h2.expression.TableFunction;
0111:        import org.h2.expression.ValueExpression;
0112:        import org.h2.expression.Variable;
0113:        import org.h2.expression.Wildcard;
0114:        import org.h2.index.Index;
0115:        import org.h2.message.Message;
0116:        import org.h2.result.SortOrder;
0117:        import org.h2.schema.Schema;
0118:        import org.h2.schema.Sequence;
0119:        import org.h2.table.Column;
0120:        import org.h2.table.FunctionTable;
0121:        import org.h2.table.IndexColumn;
0122:        import org.h2.table.RangeTable;
0123:        import org.h2.table.Table;
0124:        import org.h2.table.TableData;
0125:        import org.h2.table.TableFilter;
0126:        import org.h2.table.TableView;
0127:        import org.h2.util.ByteUtils;
0128:        import org.h2.util.MathUtils;
0129:        import org.h2.util.ObjectArray;
0130:        import org.h2.util.StringCache;
0131:        import org.h2.util.StringUtils;
0132:        import org.h2.value.CompareMode;
0133:        import org.h2.value.DataType;
0134:        import org.h2.value.Value;
0135:        import org.h2.value.ValueBoolean;
0136:        import org.h2.value.ValueBytes;
0137:        import org.h2.value.ValueDate;
0138:        import org.h2.value.ValueDecimal;
0139:        import org.h2.value.ValueInt;
0140:        import org.h2.value.ValueString;
0141:        import org.h2.value.ValueTime;
0142:        import org.h2.value.ValueTimestamp;
0143:
0144:        /**
0145:         * The parser is used to convert a SQL statement string to an command object.
0146:         */
0147:        public class Parser {
0148:
0149:            // used during the tokenizer phase
0150:            private static final int CHAR_END = -1, CHAR_VALUE = 2,
0151:                    CHAR_QUOTED = 3;
0152:            private static final int CHAR_NAME = 4, CHAR_SPECIAL_1 = 5,
0153:                    CHAR_SPECIAL_2 = 6;
0154:            private static final int CHAR_STRING = 7, CHAR_DECIMAL = 8;
0155:
0156:            // this are token types
0157:            private static final int KEYWORD = 1, IDENTIFIER = 2,
0158:                    PARAMETER = 3, END = 4, VALUE = 5;
0159:            private static final int EQUAL = 6, BIGGER_EQUAL = 7, BIGGER = 8;
0160:            private static final int SMALLER = 9, SMALLER_EQUAL = 10,
0161:                    NOT_EQUAL = 11, AT = 12;
0162:            private static final int MINUS = 17, PLUS = 18;
0163:            private static final int STRING_CONCAT = 22;
0164:            private static final int OPEN = 31, CLOSE = 32, NULL = 34,
0165:                    TRUE = 40, FALSE = 41;
0166:
0167:            private static final int CURRENT_TIMESTAMP = 42, CURRENT_DATE = 43,
0168:                    CURRENT_TIME = 44, ROWNUM = 45;
0169:
0170:            private final Database database;
0171:            private final Session session;
0172:
0173:            private int[] characterTypes;
0174:            private int currentTokenType;
0175:            private String currentToken;
0176:            private boolean currentTokenQuoted;
0177:            private Value currentValue;
0178:            private String sqlCommand, originalSQL;
0179:            private char[] sqlCommandChars;
0180:            private int lastParseIndex;
0181:            private int parseIndex;
0182:            private Prepared prepared;
0183:            private Prepared currentPrepared;
0184:            private Select currentSelect;
0185:            private ObjectArray parameters;
0186:            private String schemaName;
0187:            private ObjectArray expected;
0188:            private boolean rightsChecked;
0189:            private boolean recompileAlways;
0190:            private ObjectArray indexedParameterList;
0191:
0192:            public Parser(Session session) {
0193:                this .session = session;
0194:                database = session.getDatabase();
0195:            }
0196:
0197:            /**
0198:             * Parse the statement and prepare it for execution.
0199:             * 
0200:             * @param sql the SQL statement to parse
0201:             * @return the prepared object
0202:             */
0203:            public Prepared prepare(String sql) throws SQLException {
0204:                try {
0205:                    Prepared p = parse(sql);
0206:                    p.prepare();
0207:                    return p;
0208:                } catch (Exception e) {
0209:                    throw Message.convert(e);
0210:                }
0211:            }
0212:
0213:            /**
0214:             * Parse the statement, but don't prepare it for execution.
0215:             * 
0216:             * @param sql the SQL statement to parse
0217:             * @return the prepared object
0218:             */
0219:            public Prepared parseOnly(String sql) throws SQLException {
0220:                try {
0221:                    return parse(sql);
0222:                } catch (Exception e) {
0223:                    throw Message.convert(e);
0224:                }
0225:            }
0226:
0227:            /**
0228:             * Parse a statement or a list of statements, and prepare it for execution.
0229:             * 
0230:             * @param sql the SQL statement to parse
0231:             * @return the command object
0232:             */
0233:            public Command prepareCommand(String sql) throws SQLException {
0234:                try {
0235:                    Prepared p = parse(sql);
0236:                    p.prepare();
0237:                    Command c = new CommandContainer(this , sql, p);
0238:                    p.setCommand(c);
0239:                    if (isToken(";")) {
0240:                        String remaining = originalSQL.substring(parseIndex);
0241:                        if (remaining.trim().length() != 0) {
0242:                            CommandList list = new CommandList(this , sql, c,
0243:                                    remaining);
0244:                            // list.addCommand(c);
0245:                            // do {
0246:                            // c = parseCommand();
0247:                            // list.addCommand(c);
0248:                            // } while(currentToken.equals(";"));
0249:                            c = list;
0250:                        }
0251:                    } else if (currentTokenType != END) {
0252:                        throw getSyntaxError();
0253:                    }
0254:                    return c;
0255:                } catch (Exception e) {
0256:                    throw Message.addSQL(Message.convert(e), this .originalSQL);
0257:                }
0258:            }
0259:
0260:            private Prepared parse(String sql) throws SQLException {
0261:                Prepared p;
0262:                try {
0263:                    // first, try the fast variant
0264:                    p = parse(sql, false);
0265:                } catch (SQLException e) {
0266:                    if (e.getErrorCode() == ErrorCode.SYNTAX_ERROR_1) {
0267:                        // now, get the detailed exception
0268:                        p = parse(sql, true);
0269:                    } else {
0270:                        throw Message.addSQL(e, sql);
0271:                    }
0272:                }
0273:                p.setPrepareAlways(recompileAlways);
0274:                p.setParameterList(parameters);
0275:                return p;
0276:            }
0277:
0278:            private Prepared parse(String sql, boolean withExpectedList)
0279:                    throws SQLException {
0280:                initialize(sql);
0281:                if (withExpectedList) {
0282:                    expected = new ObjectArray();
0283:                } else {
0284:                    expected = null;
0285:                }
0286:                parameters = new ObjectArray();
0287:                currentSelect = null;
0288:                currentPrepared = null;
0289:                prepared = null;
0290:                recompileAlways = false;
0291:                indexedParameterList = null;
0292:                read();
0293:                return parsePrepared();
0294:            }
0295:
0296:            private Prepared parsePrepared() throws SQLException {
0297:                int start = lastParseIndex;
0298:                Prepared c = null;
0299:                String token = currentToken;
0300:                if (token.length() == 0) {
0301:                    c = new NoOperation(session);
0302:                } else {
0303:                    char first = token.charAt(0);
0304:                    switch (first) {
0305:                    case '(':
0306:                        c = parseSelect();
0307:                        break;
0308:                    case 'A':
0309:                        if (readIf("ALTER")) {
0310:                            c = parseAlter();
0311:                        } else if (readIf("ANALYZE")) {
0312:                            c = parseAnalyze();
0313:                        }
0314:                        break;
0315:                    case 'B':
0316:                        if (readIf("BACKUP")) {
0317:                            c = parseBackup();
0318:                        } else if (readIf("BEGIN")) {
0319:                            c = parseBegin();
0320:                        }
0321:                        break;
0322:                    case 'C':
0323:                        if (readIf("COMMIT")) {
0324:                            c = parseCommit();
0325:                        } else if (readIf("CREATE")) {
0326:                            c = parseCreate();
0327:                        } else if (readIf("CALL")) {
0328:                            c = parserCall();
0329:                        } else if (readIf("CHECKPOINT")) {
0330:                            c = parseCheckpoint();
0331:                        } else if (readIf("COMMENT")) {
0332:                            c = parseComment();
0333:                        }
0334:                        break;
0335:                    case 'D':
0336:                        if (readIf("DELETE")) {
0337:                            c = parseDelete();
0338:                        } else if (readIf("DROP")) {
0339:                            c = parseDrop();
0340:                        } else if (readIf("DECLARE")) {
0341:                            // support for DECLARE GLOBAL TEMPORARY TABLE...
0342:                            c = parseCreate();
0343:                        } else if (readIf("DEALLOCATE")) {
0344:                            c = parseDeallocate();
0345:                        }
0346:                        break;
0347:                    case 'E':
0348:                        if (readIf("EXPLAIN")) {
0349:                            c = parseExplain();
0350:                        } else if (readIf("EXECUTE")) {
0351:                            c = parseExecute();
0352:                        }
0353:                        break;
0354:                    case 'F':
0355:                        if (isToken("FROM")) {
0356:                            c = parseSelect();
0357:                        }
0358:                        break;
0359:                    case 'G':
0360:                        if (readIf("GRANT")) {
0361:                            c = parseGrantRevoke(GrantRevoke.GRANT);
0362:                        }
0363:                        break;
0364:                    case 'H':
0365:                        if (readIf("HELP")) {
0366:                            c = parseHelp();
0367:                        }
0368:                        break;
0369:                    case 'I':
0370:                        if (readIf("INSERT")) {
0371:                            c = parseInsert();
0372:                        }
0373:                        break;
0374:                    case 'M':
0375:                        if (readIf("MERGE")) {
0376:                            c = parseMerge();
0377:                        }
0378:                        break;
0379:                    case 'P':
0380:                        if (readIf("PREPARE")) {
0381:                            c = parsePrepare();
0382:                        }
0383:                        break;
0384:                    case 'R':
0385:                        if (readIf("ROLLBACK")) {
0386:                            c = parseRollback();
0387:                        } else if (readIf("REVOKE")) {
0388:                            c = parseGrantRevoke(GrantRevoke.REVOKE);
0389:                        } else if (readIf("RUNSCRIPT")) {
0390:                            c = parseRunScript();
0391:                        } else if (readIf("RELEASE")) {
0392:                            c = parseReleaseSavepoint();
0393:                        }
0394:                        break;
0395:                    case 'S':
0396:                        if (isToken("SELECT")) {
0397:                            c = parseSelect();
0398:                        } else if (readIf("SET")) {
0399:                            c = parseSet();
0400:                        } else if (readIf("SAVEPOINT")) {
0401:                            c = parseSavepoint();
0402:                        } else if (readIf("SCRIPT")) {
0403:                            c = parseScript();
0404:                        } else if (readIf("SHUTDOWN")) {
0405:                            c = parseShutdown();
0406:                        }
0407:                        break;
0408:                    case 'T':
0409:                        if (readIf("TRUNCATE")) {
0410:                            c = parseTruncate();
0411:                        }
0412:                        break;
0413:                    case 'U':
0414:                        if (readIf("UPDATE")) {
0415:                            c = parseUpdate();
0416:                        }
0417:                        break;
0418:                    case 'V':
0419:                        if (readIf("VALUES")) {
0420:                            c = parserCall();
0421:                        }
0422:                        break;
0423:                    case 'W':
0424:                        if (readIf("WITH")) {
0425:                            c = parserWith();
0426:                        }
0427:                        break;
0428:                    default:
0429:                        throw getSyntaxError();
0430:                    }
0431:                    if (indexedParameterList != null) {
0432:                        for (int i = 0; i < indexedParameterList.size(); i++) {
0433:                            if (indexedParameterList.get(i) == null) {
0434:                                indexedParameterList.set(i, new Parameter(i));
0435:                            }
0436:                        }
0437:                        parameters = indexedParameterList;
0438:                    }
0439:                    if (readIf("{")) {
0440:                        do {
0441:                            int index = (int) readLong() - 1;
0442:                            if (index < 0 || index >= parameters.size()) {
0443:                                throw getSyntaxError();
0444:                            }
0445:                            Parameter p = (Parameter) parameters.get(index);
0446:                            if (p == null) {
0447:                                throw getSyntaxError();
0448:                            }
0449:                            read(":");
0450:                            Expression expr = readExpression();
0451:                            expr = expr.optimize(session);
0452:                            p.setValue(expr.getValue(session));
0453:                            index++;
0454:                        } while (readIf(","));
0455:                        read("}");
0456:                        int len = parameters.size();
0457:                        for (int i = 0; i < len; i++) {
0458:                            Parameter p = (Parameter) parameters.get(i);
0459:                            p.checkSet();
0460:                        }
0461:                        parameters.clear();
0462:                    }
0463:                }
0464:                if (c == null) {
0465:                    throw getSyntaxError();
0466:                }
0467:                setSQL(c, null, start);
0468:                return c;
0469:            }
0470:
0471:            private SQLException getSyntaxError() {
0472:                if (expected == null || expected.size() == 0) {
0473:                    return Message.getSyntaxError(sqlCommand, parseIndex);
0474:                } else {
0475:                    StringBuffer buff = new StringBuffer();
0476:                    for (int i = 0; i < expected.size(); i++) {
0477:                        if (i > 0) {
0478:                            buff.append(", ");
0479:                        }
0480:                        buff.append(expected.get(i));
0481:                    }
0482:                    return Message.getSyntaxError(sqlCommand, parseIndex, buff
0483:                            .toString());
0484:                }
0485:            }
0486:
0487:            private Prepared parseBackup() throws SQLException {
0488:                BackupCommand command = new BackupCommand(session);
0489:                read("TO");
0490:                command.setFileName(readString());
0491:                return command;
0492:            }
0493:
0494:            private Prepared parseAnalyze() throws SQLException {
0495:                Analyze command = new Analyze(session);
0496:                if (readIf("SAMPLE_SIZE")) {
0497:                    command.setTop(getPositiveInt());
0498:                }
0499:                return command;
0500:            }
0501:
0502:            private TransactionCommand parseBegin() throws SQLException {
0503:                TransactionCommand command;
0504:                if (!readIf("WORK")) {
0505:                    readIf("TRANSACTION");
0506:                }
0507:                command = new TransactionCommand(session,
0508:                        TransactionCommand.BEGIN);
0509:                return command;
0510:            }
0511:
0512:            private TransactionCommand parseCommit() throws SQLException {
0513:                TransactionCommand command;
0514:                if (readIf("TRANSACTION")) {
0515:                    command = new TransactionCommand(session,
0516:                            TransactionCommand.COMMIT_TRANSACTION);
0517:                    command.setTransactionName(readUniqueIdentifier());
0518:                    return command;
0519:                }
0520:                command = new TransactionCommand(session,
0521:                        TransactionCommand.COMMIT);
0522:                readIf("WORK");
0523:                return command;
0524:            }
0525:
0526:            private TransactionCommand parseShutdown() throws SQLException {
0527:                int type = TransactionCommand.SHUTDOWN;
0528:                if (readIf("IMMEDIATELY")) {
0529:                    type = TransactionCommand.SHUTDOWN_IMMEDIATELY;
0530:                } else {
0531:                    if (!readIf("COMPACT")) {
0532:                        readIf("SCRIPT");
0533:                    }
0534:                }
0535:                return new TransactionCommand(session, type);
0536:            }
0537:
0538:            private TransactionCommand parseRollback() throws SQLException {
0539:                TransactionCommand command;
0540:                if (readIf("TRANSACTION")) {
0541:                    command = new TransactionCommand(session,
0542:                            TransactionCommand.ROLLBACK_TRANSACTION);
0543:                    command.setTransactionName(readUniqueIdentifier());
0544:                    return command;
0545:                }
0546:                if (readIf("TO")) {
0547:                    read("SAVEPOINT");
0548:                    command = new TransactionCommand(session,
0549:                            TransactionCommand.ROLLBACK_TO_SAVEPOINT);
0550:                    command.setSavepointName(readUniqueIdentifier());
0551:                } else {
0552:                    readIf("WORK");
0553:                    command = new TransactionCommand(session,
0554:                            TransactionCommand.ROLLBACK);
0555:                }
0556:                return command;
0557:            }
0558:
0559:            private Prepared parsePrepare() throws SQLException {
0560:                if (readIf("COMMIT")) {
0561:                    TransactionCommand command = new TransactionCommand(
0562:                            session, TransactionCommand.PREPARE_COMMIT);
0563:                    command.setTransactionName(readUniqueIdentifier());
0564:                    return command;
0565:                }
0566:                String procedureName = readAliasIdentifier();
0567:                if (readIf("(")) {
0568:                    ObjectArray list = new ObjectArray();
0569:                    for (int i = 0;; i++) {
0570:                        Column column = parseColumnForTable("C" + i);
0571:                        list.add(column);
0572:                        if (readIf(")")) {
0573:                            break;
0574:                        }
0575:                        read(",");
0576:                    }
0577:                }
0578:                read("AS");
0579:                Prepared prep = parsePrepared();
0580:                PrepareProcedure command = new PrepareProcedure(session);
0581:                command.setProcedureName(procedureName);
0582:                command.setPrepared(prep);
0583:                return command;
0584:            }
0585:
0586:            private TransactionCommand parseSavepoint() throws SQLException {
0587:                TransactionCommand command = new TransactionCommand(session,
0588:                        TransactionCommand.SAVEPOINT);
0589:                command.setSavepointName(readUniqueIdentifier());
0590:                return command;
0591:            }
0592:
0593:            private Prepared parseReleaseSavepoint() throws SQLException {
0594:                Prepared command = new NoOperation(session);
0595:                readIf("SAVEPOINT");
0596:                readUniqueIdentifier();
0597:                return command;
0598:            }
0599:
0600:            private Schema getSchema() throws SQLException {
0601:                if (schemaName == null) {
0602:                    return null;
0603:                }
0604:                Schema schema = database.findSchema(schemaName);
0605:                if (schema == null) {
0606:                    if ("SESSION".equals(schemaName)) {
0607:                        // for local temporary tables
0608:                        schema = database.getSchema(session
0609:                                .getCurrentSchemaName());
0610:                    } else {
0611:                        throw Message.getSQLException(
0612:                                ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
0613:                    }
0614:                }
0615:                return schema;
0616:            }
0617:
0618:            private Column readTableColumn(TableFilter filter)
0619:                    throws SQLException {
0620:                String tableAlias = null;
0621:                String columnName = readColumnIdentifier();
0622:                if (readIf(".")) {
0623:                    tableAlias = columnName;
0624:                    columnName = readColumnIdentifier();
0625:                    if (readIf(".")) {
0626:                        String schemaName = tableAlias;
0627:                        tableAlias = columnName;
0628:                        columnName = readColumnIdentifier();
0629:                        if (readIf(".")) {
0630:                            String catalogName = schemaName;
0631:                            schemaName = tableAlias;
0632:                            tableAlias = columnName;
0633:                            columnName = readColumnIdentifier();
0634:                            if (!catalogName.equals(database.getShortName())) {
0635:                                throw Message.getSQLException(
0636:                                        ErrorCode.DATABASE_NOT_FOUND_1,
0637:                                        catalogName);
0638:                            }
0639:                        }
0640:                        if (!schemaName.equals(filter.getTable().getSchema()
0641:                                .getName())) {
0642:                            throw Message.getSQLException(
0643:                                    ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
0644:                        }
0645:                    }
0646:                    if (!tableAlias.equals(filter.getTableAlias())) {
0647:                        throw Message
0648:                                .getSQLException(
0649:                                        ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1,
0650:                                        tableAlias);
0651:                    }
0652:                }
0653:                return filter.getTable().getColumn(columnName);
0654:            }
0655:
0656:            private Update parseUpdate() throws SQLException {
0657:                Update command = new Update(session);
0658:                currentPrepared = command;
0659:                int start = lastParseIndex;
0660:                TableFilter filter = readSimpleTableFilter();
0661:                command.setTableFilter(filter);
0662:                read("SET");
0663:                if (readIf("(")) {
0664:                    ObjectArray columns = new ObjectArray();
0665:                    do {
0666:                        Column column = readTableColumn(filter);
0667:                        columns.add(column);
0668:                    } while (readIf(","));
0669:                    read(")");
0670:                    read("=");
0671:                    Expression expression = readExpression();
0672:                    for (int i = 0; i < columns.size(); i++) {
0673:                        Column column = (Column) columns.get(i);
0674:                        Function f = Function
0675:                                .getFunction(database, "ARRAY_GET");
0676:                        f.setParameter(0, expression);
0677:                        f.setParameter(1, ValueExpression.get(ValueInt
0678:                                .get(i + 1)));
0679:                        f.doneWithParameters();
0680:                        command.setAssignment(column, f);
0681:                    }
0682:                } else {
0683:                    do {
0684:                        Column column = readTableColumn(filter);
0685:                        read("=");
0686:                        Expression expression;
0687:                        if (readIf("DEFAULT")) {
0688:                            expression = ValueExpression.DEFAULT;
0689:                        } else {
0690:                            expression = readExpression();
0691:                        }
0692:                        command.setAssignment(column, expression);
0693:                    } while (readIf(","));
0694:                }
0695:                if (readIf("WHERE")) {
0696:                    Expression condition = readExpression();
0697:                    command.setCondition(condition);
0698:                }
0699:                setSQL(command, "UPDATE", start);
0700:                return command;
0701:            }
0702:
0703:            private TableFilter readSimpleTableFilter() throws SQLException {
0704:                Table table = readTableOrView();
0705:                String alias = null;
0706:                if (readIf("AS")) {
0707:                    alias = readAliasIdentifier();
0708:                } else if (currentTokenType == IDENTIFIER) {
0709:                    if (!"SET".equals(currentToken)) {
0710:                        // SET is not a keyword (PostgreSQL supports it as a table name)
0711:                        alias = readAliasIdentifier();
0712:                    }
0713:                }
0714:                return new TableFilter(session, table, alias, rightsChecked,
0715:                        currentSelect);
0716:            }
0717:
0718:            private Delete parseDelete() throws SQLException {
0719:                Delete command = new Delete(session);
0720:                currentPrepared = command;
0721:                int start = lastParseIndex;
0722:                readIf("FROM");
0723:                TableFilter filter = readSimpleTableFilter();
0724:                command.setTableFilter(filter);
0725:                if (readIf("WHERE")) {
0726:                    Expression condition = readExpression();
0727:                    command.setCondition(condition);
0728:                }
0729:                setSQL(command, "DELETE", start);
0730:                return command;
0731:            }
0732:
0733:            private IndexColumn[] parseIndexColumnList() throws SQLException {
0734:                ObjectArray columns = new ObjectArray();
0735:                do {
0736:                    IndexColumn column = new IndexColumn();
0737:                    column.columnName = readColumnIdentifier();
0738:                    columns.add(column);
0739:                    if (readIf("ASC")) {
0740:                        // ignore
0741:                    } else if (readIf("DESC")) {
0742:                        column.sortType = SortOrder.DESCENDING;
0743:                    }
0744:                    if (readIf("NULLS")) {
0745:                        if (readIf("FIRST")) {
0746:                            column.sortType |= SortOrder.NULLS_FIRST;
0747:                        } else {
0748:                            read("LAST");
0749:                            column.sortType |= SortOrder.NULLS_LAST;
0750:                        }
0751:                    } else {
0752:
0753:                    }
0754:                } while (readIf(","));
0755:                read(")");
0756:                IndexColumn[] cols = new IndexColumn[columns.size()];
0757:                columns.toArray(cols);
0758:                return cols;
0759:            }
0760:
0761:            private String[] parseColumnList() throws SQLException {
0762:                ObjectArray columns = new ObjectArray();
0763:                do {
0764:                    String columnName = readColumnIdentifier();
0765:                    columns.add(columnName);
0766:                } while (readIf(","));
0767:                read(")");
0768:                String[] cols = new String[columns.size()];
0769:                columns.toArray(cols);
0770:                return cols;
0771:            }
0772:
0773:            private Column[] parseColumnList(Table table) throws SQLException {
0774:                ObjectArray columns = new ObjectArray();
0775:                HashSet set = new HashSet();
0776:                if (!readIf(")")) {
0777:                    do {
0778:                        Column column = table.getColumn(readColumnIdentifier());
0779:                        if (!set.add(column)) {
0780:                            throw Message.getSQLException(
0781:                                    ErrorCode.DUPLICATE_COLUMN_NAME_1, column
0782:                                            .getSQL());
0783:                        }
0784:                        columns.add(column);
0785:                    } while (readIf(","));
0786:                    read(")");
0787:                }
0788:                Column[] cols = new Column[columns.size()];
0789:                columns.toArray(cols);
0790:                return cols;
0791:            }
0792:
0793:            private Prepared parseHelp() throws SQLException {
0794:                StringBuffer buff = new StringBuffer(
0795:                        "SELECT * FROM INFORMATION_SCHEMA.HELP");
0796:                int i = 0;
0797:                while (currentTokenType != END) {
0798:                    String s = currentToken;
0799:                    read();
0800:                    if (i == 0) {
0801:                        buff.append(" WHERE ");
0802:                    } else {
0803:                        buff.append(" AND ");
0804:                    }
0805:                    i++;
0806:                    buff.append("UPPER(TOPIC) LIKE ");
0807:                    buff.append(StringUtils.quoteStringSQL("%" + s + "%"));
0808:                }
0809:                return session.prepare(buff.toString());
0810:            }
0811:
0812:            private Merge parseMerge() throws SQLException {
0813:                Merge command = new Merge(session);
0814:                currentPrepared = command;
0815:                read("INTO");
0816:                Table table = readTableOrView();
0817:                command.setTable(table);
0818:                if (readIf("(")) {
0819:                    Column[] columns = parseColumnList(table);
0820:                    command.setColumns(columns);
0821:                }
0822:                if (readIf("KEY")) {
0823:                    read("(");
0824:                    Column[] keys = parseColumnList(table);
0825:                    command.setKeys(keys);
0826:                }
0827:                if (readIf("VALUES")) {
0828:                    do {
0829:                        ObjectArray values = new ObjectArray();
0830:                        read("(");
0831:                        if (!readIf(")")) {
0832:                            do {
0833:                                if (readIf("DEFAULT")) {
0834:                                    values.add(null);
0835:                                } else {
0836:                                    values.add(readExpression());
0837:                                }
0838:                            } while (readIf(","));
0839:                            read(")");
0840:                        }
0841:                        Expression[] expr = new Expression[values.size()];
0842:                        values.toArray(expr);
0843:                        command.addRow(expr);
0844:                    } while (readIf(","));
0845:                } else {
0846:                    command.setQuery(parseSelect());
0847:                }
0848:                return command;
0849:            }
0850:
0851:            private Insert parseInsert() throws SQLException {
0852:                Insert command = new Insert(session);
0853:                currentPrepared = command;
0854:                read("INTO");
0855:                Table table = readTableOrView();
0856:                command.setTable(table);
0857:                if (readIf("(")) {
0858:                    Column[] columns = parseColumnList(table);
0859:                    command.setColumns(columns);
0860:                }
0861:                if (readIf("DEFAULT")) {
0862:                    read("VALUES");
0863:                    Expression[] expr = new Expression[0];
0864:                    command.addRow(expr);
0865:                } else if (readIf("VALUES")) {
0866:                    do {
0867:                        ObjectArray values = new ObjectArray();
0868:                        read("(");
0869:                        if (!readIf(")")) {
0870:                            do {
0871:                                if (readIf("DEFAULT")) {
0872:                                    values.add(null);
0873:                                } else {
0874:                                    values.add(readExpression());
0875:                                }
0876:                            } while (readIf(","));
0877:                            read(")");
0878:                        }
0879:                        Expression[] expr = new Expression[values.size()];
0880:                        values.toArray(expr);
0881:                        command.addRow(expr);
0882:                    } while (readIf(","));
0883:                } else {
0884:                    command.setQuery(parseSelect());
0885:                }
0886:                return command;
0887:            }
0888:
0889:            private TableFilter readTableFilter(boolean fromOuter)
0890:                    throws SQLException {
0891:                Table table;
0892:                String alias = null;
0893:                Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
0894:                if (readIf("(")) {
0895:                    if (isToken("SELECT") || isToken("FROM")) {
0896:                        int start = lastParseIndex;
0897:                        int paramIndex = parameters.size();
0898:                        Query query = parseSelectUnion();
0899:                        read(")");
0900:                        query = parseSelectUnionExtension(query, start, true);
0901:                        ObjectArray params = new ObjectArray();
0902:                        for (int i = paramIndex; i < parameters.size(); i++) {
0903:                            params.add(parameters.get(i));
0904:                        }
0905:                        query.setParameterList(params);
0906:                        query.init();
0907:                        Session s;
0908:                        if (prepared != null && prepared instanceof  CreateView) {
0909:                            s = database.getSystemSession();
0910:                        } else {
0911:                            s = session;
0912:                        }
0913:                        table = TableView.createTempView(s, session.getUser(),
0914:                                query);
0915:                        alias = table.getName();
0916:                    } else {
0917:                        TableFilter top = readTableFilter(fromOuter);
0918:                        top = readJoin(top, currentSelect, fromOuter);
0919:                        read(")");
0920:                        alias = readFromAlias(null);
0921:                        if (alias != null) {
0922:                            top.setAlias(alias);
0923:                        }
0924:                        return top;
0925:                    }
0926:                } else {
0927:                    String tableName = readIdentifierWithSchema(null);
0928:                    if (readIf("(")) {
0929:                        if (tableName.equals(RangeTable.NAME)) {
0930:                            long min = readLong();
0931:                            read(",");
0932:                            long max = readLong();
0933:                            read(")");
0934:                            table = new RangeTable(mainSchema, min, max);
0935:                        } else {
0936:                            Expression func = readFunction(tableName);
0937:                            if (!(func instanceof  FunctionCall)) {
0938:                                throw getSyntaxError();
0939:                            }
0940:                            table = new FunctionTable(mainSchema, session,
0941:                                    (FunctionCall) func);
0942:                        }
0943:                    } else if ("DUAL".equals(tableName)) {
0944:                        table = new RangeTable(mainSchema, 1, 1);
0945:                    } else {
0946:                        table = readTableOrView(tableName);
0947:                    }
0948:                }
0949:                alias = readFromAlias(alias);
0950:                return new TableFilter(session, table, alias, rightsChecked,
0951:                        currentSelect);
0952:            }
0953:
0954:            String readFromAlias(String alias) throws SQLException {
0955:                if (readIf("AS")) {
0956:                    alias = readAliasIdentifier();
0957:                } else if (currentTokenType == IDENTIFIER) {
0958:                    // left and right are not keywords (because they are functions as
0959:                    // well)
0960:                    if (!isToken("LEFT") && !isToken("RIGHT")
0961:                            && !isToken("FULL")) {
0962:                        alias = readAliasIdentifier();
0963:                    }
0964:                }
0965:                return alias;
0966:            }
0967:
0968:            private Prepared parseTruncate() throws SQLException {
0969:                read("TABLE");
0970:                Table table = readTableOrView();
0971:                TruncateTable command = new TruncateTable(session);
0972:                command.setTable(table);
0973:                return command;
0974:            }
0975:
0976:            private boolean readIfExists(boolean ifExists) throws SQLException {
0977:                if (readIf("IF")) {
0978:                    read("EXISTS");
0979:                    ifExists = true;
0980:                }
0981:                return ifExists;
0982:            }
0983:
0984:            private Prepared parseComment() throws SQLException {
0985:                int type = 0;
0986:                read("ON");
0987:                boolean column = false;
0988:                if (readIf("TABLE") || readIf("VIEW")) {
0989:                    type = DbObject.TABLE_OR_VIEW;
0990:                } else if (readIf("COLUMN")) {
0991:                    column = true;
0992:                    type = DbObject.TABLE_OR_VIEW;
0993:                } else if (readIf("CONSTANT")) {
0994:                    type = DbObject.CONSTANT;
0995:                } else if (readIf("CONSTRAINT")) {
0996:                    type = DbObject.CONSTRAINT;
0997:                } else if (readIf("ALIAS")) {
0998:                    type = DbObject.FUNCTION_ALIAS;
0999:                } else if (readIf("INDEX")) {
1000:                    type = DbObject.INDEX;
1001:                } else if (readIf("ROLE")) {
1002:                    type = DbObject.ROLE;
1003:                } else if (readIf("SCHEMA")) {
1004:                    type = DbObject.SCHEMA;
1005:                } else if (readIf("SEQUENCE")) {
1006:                    type = DbObject.SEQUENCE;
1007:                } else if (readIf("TRIGGER")) {
1008:                    type = DbObject.TRIGGER;
1009:                } else if (readIf("USER")) {
1010:                    type = DbObject.USER;
1011:                } else if (readIf("DOMAIN")) {
1012:                    type = DbObject.USER_DATATYPE;
1013:                } else {
1014:                    throw getSyntaxError();
1015:                }
1016:                SetComment command = new SetComment(session);
1017:                String objectName = readIdentifierWithSchema();
1018:                if (column) {
1019:                    String columnName = objectName;
1020:                    objectName = schemaName;
1021:                    schemaName = session.getCurrentSchemaName();
1022:                    if (readIf(".")) {
1023:                        schemaName = objectName;
1024:                        objectName = columnName;
1025:                        columnName = readUniqueIdentifier();
1026:                    }
1027:                    command.setColumn(true);
1028:                    command.setColumnName(columnName);
1029:                }
1030:                command.setSchemaName(schemaName);
1031:                command.setObjectName(objectName);
1032:                command.setObjectType(type);
1033:                read("IS");
1034:                command.setCommentExpression(readExpression());
1035:                return command;
1036:            }
1037:
1038:            private Prepared parseDrop() throws SQLException {
1039:                if (readIf("TABLE")) {
1040:                    boolean ifExists = readIfExists(false);
1041:                    String tableName = readIdentifierWithSchema();
1042:                    DropTable command = new DropTable(session, getSchema());
1043:                    command.setTableName(tableName);
1044:                    while (readIf(",")) {
1045:                        tableName = readIdentifierWithSchema();
1046:                        DropTable next = new DropTable(session, getSchema());
1047:                        next.setTableName(tableName);
1048:                        command.addNextDropTable(next);
1049:                    }
1050:                    ifExists = readIfExists(ifExists);
1051:                    command.setIfExists(ifExists);
1052:                    if (readIf("CASCADE")) {
1053:                        readIf("CONSTRAINTS");
1054:                    }
1055:                    return command;
1056:                } else if (readIf("INDEX")) {
1057:                    boolean ifExists = readIfExists(false);
1058:                    String indexName = readIdentifierWithSchema();
1059:                    DropIndex command = new DropIndex(session, getSchema());
1060:                    command.setIndexName(indexName);
1061:                    ifExists = readIfExists(ifExists);
1062:                    command.setIfExists(ifExists);
1063:                    return command;
1064:                } else if (readIf("USER")) {
1065:                    boolean ifExists = readIfExists(false);
1066:                    DropUser command = new DropUser(session);
1067:                    command.setUserName(readUniqueIdentifier());
1068:                    ifExists = readIfExists(ifExists);
1069:                    readIf("CASCADE");
1070:                    command.setIfExists(ifExists);
1071:                    return command;
1072:                } else if (readIf("SEQUENCE")) {
1073:                    boolean ifExists = readIfExists(false);
1074:                    String sequenceName = readIdentifierWithSchema();
1075:                    DropSequence command = new DropSequence(session,
1076:                            getSchema());
1077:                    command.setSequenceName(sequenceName);
1078:                    ifExists = readIfExists(ifExists);
1079:                    command.setIfExists(ifExists);
1080:                    return command;
1081:                } else if (readIf("CONSTANT")) {
1082:                    boolean ifExists = readIfExists(false);
1083:                    String constantName = readIdentifierWithSchema();
1084:                    DropConstant command = new DropConstant(session,
1085:                            getSchema());
1086:                    command.setConstantName(constantName);
1087:                    ifExists = readIfExists(ifExists);
1088:                    command.setIfExists(ifExists);
1089:                    return command;
1090:                } else if (readIf("TRIGGER")) {
1091:                    boolean ifExists = readIfExists(false);
1092:                    String triggerName = readIdentifierWithSchema();
1093:                    DropTrigger command = new DropTrigger(session, getSchema());
1094:                    command.setTriggerName(triggerName);
1095:                    ifExists = readIfExists(ifExists);
1096:                    command.setIfExists(ifExists);
1097:                    return command;
1098:                } else if (readIf("VIEW")) {
1099:                    boolean ifExists = readIfExists(false);
1100:                    String viewName = readIdentifierWithSchema();
1101:                    DropView command = new DropView(session, getSchema());
1102:                    command.setViewName(viewName);
1103:                    ifExists = readIfExists(ifExists);
1104:                    command.setIfExists(ifExists);
1105:                    return command;
1106:                } else if (readIf("ROLE")) {
1107:                    boolean ifExists = readIfExists(false);
1108:                    DropRole command = new DropRole(session);
1109:                    command.setRoleName(readUniqueIdentifier());
1110:                    ifExists = readIfExists(ifExists);
1111:                    command.setIfExists(ifExists);
1112:                    return command;
1113:                    // TODO role: support role names SELECT | DELETE | INSERT | UPDATE |
1114:                    // ALL? does quoting work?
1115:                } else if (readIf("ALIAS")) {
1116:                    boolean ifExists = readIfExists(false);
1117:                    DropFunctionAlias command = new DropFunctionAlias(session);
1118:                    command.setAliasName(readUniqueIdentifier());
1119:                    ifExists = readIfExists(ifExists);
1120:                    command.setIfExists(ifExists);
1121:                    return command;
1122:                } else if (readIf("SCHEMA")) {
1123:                    boolean ifExists = readIfExists(false);
1124:                    DropSchema command = new DropSchema(session);
1125:                    command.setSchemaName(readUniqueIdentifier());
1126:                    ifExists = readIfExists(ifExists);
1127:                    command.setIfExists(ifExists);
1128:                    return command;
1129:                } else if (readIf("ALL")) {
1130:                    read("OBJECTS");
1131:                    DropDatabase command = new DropDatabase(session);
1132:                    command.setDropAllObjects(true);
1133:                    if (readIf("DELETE")) {
1134:                        read("FILES");
1135:                        command.setDeleteFiles(true);
1136:                    }
1137:                    return command;
1138:                } else if (readIf("DOMAIN")) {
1139:                    return parseDropUserDataType();
1140:                } else if (readIf("TYPE")) {
1141:                    return parseDropUserDataType();
1142:                } else if (readIf("DATATYPE")) {
1143:                    return parseDropUserDataType();
1144:                } else if (readIf("AGGREGATE")) {
1145:                    return parseDropAggregate();
1146:                }
1147:                throw getSyntaxError();
1148:            }
1149:
1150:            DropUserDataType parseDropUserDataType() throws SQLException {
1151:                boolean ifExists = readIfExists(false);
1152:                DropUserDataType command = new DropUserDataType(session);
1153:                command.setTypeName(readUniqueIdentifier());
1154:                ifExists = readIfExists(ifExists);
1155:                command.setIfExists(ifExists);
1156:                return command;
1157:            }
1158:
1159:            DropAggregate parseDropAggregate() throws SQLException {
1160:                boolean ifExists = readIfExists(false);
1161:                DropAggregate command = new DropAggregate(session);
1162:                command.setName(readUniqueIdentifier());
1163:                ifExists = readIfExists(ifExists);
1164:                command.setIfExists(ifExists);
1165:                return command;
1166:            }
1167:
1168:            private TableFilter readJoin(TableFilter top, Select command,
1169:                    boolean fromOuter) throws SQLException {
1170:                TableFilter last = top;
1171:                while (true) {
1172:                    if (readIf("RIGHT")) {
1173:                        readIf("OUTER");
1174:                        read("JOIN");
1175:                        // the right hand side is the 'inner' table usually
1176:                        TableFilter newTop = readTableFilter(fromOuter);
1177:                        Expression on = null;
1178:                        if (readIf("ON")) {
1179:                            on = readExpression();
1180:                        }
1181:                        newTop.addJoin(top, true, on);
1182:                        top = newTop;
1183:                        last = newTop;
1184:                    } else if (readIf("LEFT")) {
1185:                        readIf("OUTER");
1186:                        read("JOIN");
1187:                        TableFilter join = readTableFilter(true);
1188:                        Expression on = null;
1189:                        if (readIf("ON")) {
1190:                            on = readExpression();
1191:                        }
1192:                        top.addJoin(join, true, on);
1193:                        last = join;
1194:                    } else if (readIf("FULL")) {
1195:                        throw this .getSyntaxError();
1196:                    } else if (readIf("INNER")) {
1197:                        read("JOIN");
1198:                        TableFilter join = readTableFilter(fromOuter);
1199:                        Expression on = null;
1200:                        if (readIf("ON")) {
1201:                            on = readExpression();
1202:                        }
1203:                        top.addJoin(join, fromOuter, on);
1204:                        last = join;
1205:                    } else if (readIf("JOIN")) {
1206:                        TableFilter join = readTableFilter(fromOuter);
1207:                        Expression on = null;
1208:                        if (readIf("ON")) {
1209:                            on = readExpression();
1210:                        }
1211:                        top.addJoin(join, fromOuter, on);
1212:                        last = join;
1213:                    } else if (readIf("CROSS")) {
1214:                        read("JOIN");
1215:                        TableFilter join = readTableFilter(fromOuter);
1216:                        top.addJoin(join, fromOuter, null);
1217:                        last = join;
1218:                    } else if (readIf("NATURAL")) {
1219:                        read("JOIN");
1220:                        TableFilter join = readTableFilter(fromOuter);
1221:                        Column[] tableCols = last.getTable().getColumns();
1222:                        Column[] joinCols = join.getTable().getColumns();
1223:                        String tableSchema = last.getTable().getSchema()
1224:                                .getName();
1225:                        String joinSchema = join.getTable().getSchema()
1226:                                .getName();
1227:                        Expression on = null;
1228:                        for (int t = 0; t < tableCols.length; t++) {
1229:                            String tableColumnName = tableCols[t].getName();
1230:                            for (int j = 0; j < joinCols.length; j++) {
1231:                                String joinColumnName = joinCols[j].getName();
1232:                                if (tableColumnName.equals(joinColumnName)) {
1233:                                    Expression tableExpr = new ExpressionColumn(
1234:                                            database, tableSchema, last
1235:                                                    .getTableAlias(),
1236:                                            tableColumnName);
1237:                                    Expression joinExpr = new ExpressionColumn(
1238:                                            database, joinSchema, join
1239:                                                    .getTableAlias(),
1240:                                            joinColumnName);
1241:                                    Expression equal = new Comparison(session,
1242:                                            Comparison.EQUAL, tableExpr,
1243:                                            joinExpr);
1244:                                    if (on == null) {
1245:                                        on = equal;
1246:                                    } else {
1247:                                        on = new ConditionAndOr(
1248:                                                ConditionAndOr.AND, on, equal);
1249:                                    }
1250:                                }
1251:                            }
1252:                        }
1253:                        top.addJoin(join, fromOuter, on);
1254:                        last = join;
1255:                    } else {
1256:                        break;
1257:                    }
1258:                }
1259:                return top;
1260:            }
1261:
1262:            private Prepared parseExecute() throws SQLException {
1263:                ExecuteProcedure command = new ExecuteProcedure(session);
1264:                String procedureName = readAliasIdentifier();
1265:                Procedure p = session.getProcedure(procedureName);
1266:                if (p == null) {
1267:                    throw Message
1268:                            .getSQLException(
1269:                                    ErrorCode.FUNCTION_ALIAS_NOT_FOUND_1,
1270:                                    procedureName);
1271:                }
1272:                command.setProcedure(p);
1273:                if (readIf("(")) {
1274:                    for (int i = 0;; i++) {
1275:                        command.setExpression(i, readExpression());
1276:                        if (readIf(")")) {
1277:                            break;
1278:                        }
1279:                        read(",");
1280:                    }
1281:                }
1282:                return command;
1283:            }
1284:
1285:            private DeallocateProcedure parseDeallocate() throws SQLException {
1286:                readIf("PLAN");
1287:                String procedureName = readAliasIdentifier();
1288:                DeallocateProcedure command = new DeallocateProcedure(session);
1289:                command.setProcedureName(procedureName);
1290:                return command;
1291:            }
1292:
1293:            private ExplainPlan parseExplain() throws SQLException {
1294:                ExplainPlan command = new ExplainPlan(session);
1295:                readIf("PLAN");
1296:                readIf("FOR");
1297:                if (isToken("SELECT") || isToken("FROM") || isToken("(")) {
1298:                    command.setCommand(parseSelect());
1299:                } else if (readIf("DELETE")) {
1300:                    command.setCommand(parseDelete());
1301:                } else if (readIf("UPDATE")) {
1302:                    command.setCommand(parseUpdate());
1303:                } else if (readIf("INSERT")) {
1304:                    command.setCommand(parseInsert());
1305:                } else if (readIf("MERGE")) {
1306:                    command.setCommand(parseMerge());
1307:                } else {
1308:                    throw getSyntaxError();
1309:                }
1310:                return command;
1311:            }
1312:
1313:            private Query parseSelect() throws SQLException {
1314:                int paramIndex = parameters.size();
1315:                Query command = parseSelectUnion();
1316:                ObjectArray params = new ObjectArray();
1317:                for (int i = paramIndex; i < parameters.size(); i++) {
1318:                    params.add(parameters.get(i));
1319:                }
1320:                command.setParameterList(params);
1321:                command.init();
1322:                return command;
1323:            }
1324:
1325:            private Query parseSelectUnion() throws SQLException {
1326:                int start = lastParseIndex;
1327:                Query command = parseSelectSub();
1328:                return parseSelectUnionExtension(command, start, false);
1329:            }
1330:
1331:            private Query parseSelectUnionExtension(Query command, int start,
1332:                    boolean unionOnly) throws SQLException {
1333:                while (true) {
1334:                    if (readIf("UNION")) {
1335:                        SelectUnion union = new SelectUnion(session, command);
1336:                        if (readIf("ALL")) {
1337:                            union.setUnionType(SelectUnion.UNION_ALL);
1338:                        } else {
1339:                            readIf("DISTINCT");
1340:                            union.setUnionType(SelectUnion.UNION);
1341:                        }
1342:                        union.setRight(parseSelectSub());
1343:                        command = union;
1344:                    } else if (readIf("MINUS") || readIf("EXCEPT")) {
1345:                        SelectUnion union = new SelectUnion(session, command);
1346:                        union.setUnionType(SelectUnion.EXCEPT);
1347:                        union.setRight(parseSelectSub());
1348:                        command = union;
1349:                    } else if (readIf("INTERSECT")) {
1350:                        SelectUnion union = new SelectUnion(session, command);
1351:                        union.setUnionType(SelectUnion.INTERSECT);
1352:                        union.setRight(parseSelectSub());
1353:                        command = union;
1354:                    } else {
1355:                        break;
1356:                    }
1357:                }
1358:                if (!unionOnly && readIf("ORDER")) {
1359:                    read("BY");
1360:                    Select oldSelect = currentSelect;
1361:                    if (command instanceof  Select) {
1362:                        currentSelect = (Select) command;
1363:                    }
1364:                    ObjectArray orderList = new ObjectArray();
1365:                    do {
1366:                        boolean canBeNumber = true;
1367:                        if (readIf("=")) {
1368:                            canBeNumber = false;
1369:                        }
1370:                        SelectOrderBy order = new SelectOrderBy();
1371:                        Expression expr = readExpression();
1372:                        if (canBeNumber && expr instanceof  ValueExpression
1373:                                && expr.getType() == Value.INT) {
1374:                            order.columnIndexExpr = expr;
1375:                        } else if (expr instanceof  Parameter) {
1376:                            recompileAlways = true;
1377:                            order.columnIndexExpr = expr;
1378:                        } else {
1379:                            order.expression = expr;
1380:                        }
1381:                        if (readIf("DESC")) {
1382:                            order.descending = true;
1383:                        } else {
1384:                            readIf("ASC");
1385:                        }
1386:                        if (readIf("NULLS")) {
1387:                            if (readIf("FIRST")) {
1388:                                order.nullsFirst = true;
1389:                            } else {
1390:                                read("LAST");
1391:                                order.nullsLast = true;
1392:                            }
1393:                        }
1394:                        orderList.add(order);
1395:                    } while (readIf(","));
1396:                    command.setOrder(orderList);
1397:                    currentSelect = oldSelect;
1398:                }
1399:                if (!unionOnly && readIf("LIMIT")) {
1400:                    Select temp = currentSelect;
1401:                    // make sure aggregate functions will not work here
1402:                    currentSelect = null;
1403:                    Expression limit = readExpression().optimize(session);
1404:                    command.setLimit(limit);
1405:                    if (readIf("OFFSET")) {
1406:                        Expression offset = readExpression().optimize(session);
1407:                        command.setOffset(offset);
1408:                    } else if (readIf(",")) {
1409:                        // MySQL: [offset, ] rowcount
1410:                        Expression offset = limit;
1411:                        limit = readExpression().optimize(session);
1412:                        command.setOffset(offset);
1413:                        command.setLimit(limit);
1414:                    }
1415:                    if (readIf("SAMPLE_SIZE")) {
1416:                        command.setSampleSize(getPositiveInt());
1417:                    }
1418:                    currentSelect = temp;
1419:                }
1420:                if (!unionOnly && readIf("FOR")) {
1421:                    if (readIf("UPDATE")) {
1422:                        if (readIf("OF")) {
1423:                            do {
1424:                                readIdentifierWithSchema();
1425:                            } while (readIf(","));
1426:                        } else if (readIf("NOWAIT")) {
1427:                            // TODO parser: select for update nowait: should not wait
1428:                        } else if (readIf("WITH")) {
1429:                            // Hibernate / Derby support
1430:                            read("RR");
1431:                        }
1432:                        command.setForUpdate(true);
1433:                    } else if (readIf("READ")) {
1434:                        read("ONLY");
1435:                        if (readIf("WITH")) {
1436:                            read("RS");
1437:                        }
1438:                    }
1439:                }
1440:                setSQL(command, null, start);
1441:                return command;
1442:            }
1443:
1444:            private Query parseSelectSub() throws SQLException {
1445:                if (readIf("(")) {
1446:                    Query command = parseSelectUnion();
1447:                    read(")");
1448:                    return command;
1449:                }
1450:                Select select = parseSelectSimple();
1451:                return select;
1452:            }
1453:
1454:            private void parseSelectSimpleFromPart(Select command)
1455:                    throws SQLException {
1456:                do {
1457:                    TableFilter filter = readTableFilter(false);
1458:                    parseJoinTableFilter(filter, command);
1459:                } while (readIf(","));
1460:            }
1461:
1462:            private void parseJoinTableFilter(TableFilter top, Select command)
1463:                    throws SQLException {
1464:                top = readJoin(top, command, top.isJoinOuter());
1465:                command.addTableFilter(top, true);
1466:                boolean isOuter = false;
1467:                while (true) {
1468:                    TableFilter join = top.getJoin();
1469:                    if (join == null) {
1470:                        break;
1471:                    }
1472:                    isOuter = isOuter | join.isJoinOuter();
1473:                    if (isOuter) {
1474:                        command.addTableFilter(join, false);
1475:                    } else {
1476:                        // make flat so the optimizer can work better
1477:                        Expression on = join.getJoinCondition();
1478:                        if (on != null) {
1479:                            command.addCondition(on);
1480:                        }
1481:                        join.removeJoinCondition();
1482:                        top.removeJoin();
1483:                        command.addTableFilter(join, true);
1484:                    }
1485:                    top = join;
1486:                }
1487:            }
1488:
1489:            private void parseSelectSimpleSelectPart(Select command)
1490:                    throws SQLException {
1491:                Select temp = currentSelect;
1492:                // make sure aggregate functions will not work in TOP and LIMIT
1493:                currentSelect = null;
1494:                if (readIf("TOP")) {
1495:                    // can't read more complex expressions here because
1496:                    // SELECT TOP 1 +? A FROM TEST could mean
1497:                    // SELECT TOP (1+?) A FROM TEST or
1498:                    // SELECT TOP 1 (+?) AS A FROM TEST
1499:                    Expression limit = readTerm().optimize(session);
1500:                    command.setLimit(limit);
1501:                } else if (readIf("LIMIT")) {
1502:                    Expression offset = readTerm().optimize(session);
1503:                    command.setOffset(offset);
1504:                    Expression limit = readTerm().optimize(session);
1505:                    command.setLimit(limit);
1506:                }
1507:                currentSelect = temp;
1508:                if (readIf("DISTINCT")) {
1509:                    command.setDistinct(true);
1510:                } else {
1511:                    readIf("ALL");
1512:                }
1513:                ObjectArray expressions = new ObjectArray();
1514:                do {
1515:                    if (readIf("*")) {
1516:                        expressions.add(new Wildcard(null, null));
1517:                    } else {
1518:                        Expression expr = readExpression();
1519:                        if (readIf("AS") || currentTokenType == IDENTIFIER) {
1520:                            String alias = readAliasIdentifier();
1521:                            expr = new Alias(expr, alias);
1522:                        }
1523:                        expressions.add(expr);
1524:                    }
1525:                } while (readIf(","));
1526:                command.setExpressions(expressions);
1527:            }
1528:
1529:            private Select parseSelectSimple() throws SQLException {
1530:                boolean fromFirst;
1531:                if (readIf("SELECT")) {
1532:                    fromFirst = false;
1533:                } else if (readIf("FROM")) {
1534:                    fromFirst = true;
1535:                } else {
1536:                    throw getSyntaxError();
1537:                }
1538:                Select command = new Select(session);
1539:                int start = lastParseIndex;
1540:                Select oldSelect = currentSelect;
1541:                currentSelect = command;
1542:                currentPrepared = command;
1543:                if (fromFirst) {
1544:                    parseSelectSimpleFromPart(command);
1545:                    read("SELECT");
1546:                    parseSelectSimpleSelectPart(command);
1547:                } else {
1548:                    parseSelectSimpleSelectPart(command);
1549:                    if (!readIf("FROM")) {
1550:                        // select without FROM: convert to SELECT ... FROM
1551:                        // SYSTEM_RANGE(1,1)
1552:                        Schema main = database
1553:                                .findSchema(Constants.SCHEMA_MAIN);
1554:                        Table dual = new RangeTable(main, 1, 1);
1555:                        TableFilter filter = new TableFilter(session, dual,
1556:                                null, rightsChecked, currentSelect);
1557:                        command.addTableFilter(filter, true);
1558:                    } else {
1559:                        parseSelectSimpleFromPart(command);
1560:                    }
1561:                }
1562:                if (readIf("WHERE")) {
1563:                    Expression condition = readExpression();
1564:                    command.addCondition(condition);
1565:                }
1566:                // the group by is read for the outer select (or not a select)
1567:                // so that columns that are not grouped can be used
1568:                currentSelect = oldSelect;
1569:                if (readIf("GROUP")) {
1570:                    read("BY");
1571:                    command.setGroupQuery();
1572:                    ObjectArray list = new ObjectArray();
1573:                    do {
1574:                        Expression expr = readExpression();
1575:                        list.add(expr);
1576:                    } while (readIf(","));
1577:                    command.setGroupBy(list);
1578:                }
1579:                currentSelect = command;
1580:                if (readIf("HAVING")) {
1581:                    command.setGroupQuery();
1582:                    Expression condition = readExpression();
1583:                    command.setHaving(condition);
1584:                }
1585:                command.setParameterList(parameters);
1586:                currentSelect = oldSelect;
1587:                setSQL(command, "SELECT", start);
1588:                return command;
1589:            }
1590:
1591:            private void setSQL(Prepared command, String start, int startIndex) {
1592:                String sql = originalSQL.substring(startIndex, lastParseIndex)
1593:                        .trim();
1594:                if (start != null) {
1595:                    sql = start + " " + sql;
1596:                }
1597:                command.setSQL(sql);
1598:            }
1599:
1600:            private Expression readExpression() throws SQLException {
1601:                Expression r = readAnd();
1602:                while (readIf("OR")) {
1603:                    r = new ConditionAndOr(ConditionAndOr.OR, r, readAnd());
1604:                }
1605:                return r;
1606:            }
1607:
1608:            private Expression readAnd() throws SQLException {
1609:                Expression r = readCondition();
1610:                while (readIf("AND")) {
1611:                    r = new ConditionAndOr(ConditionAndOr.AND, r,
1612:                            readCondition());
1613:                }
1614:                return r;
1615:            }
1616:
1617:            private Expression readCondition() throws SQLException {
1618:                // TODO parser: should probably use switch case for performance
1619:                if (readIf("NOT")) {
1620:                    return new ConditionNot(readCondition());
1621:                }
1622:                if (readIf("EXISTS")) {
1623:                    read("(");
1624:                    Query query = parseSelect();
1625:                    // can not reduce expression because it might be a union except
1626:                    // query with distinct
1627:                    read(")");
1628:                    return new ConditionExists(query);
1629:                }
1630:                Expression r = readConcat();
1631:                while (true) {
1632:                    // special case: NOT NULL is not part of an expression (as in CREATE
1633:                    // TABLE TEST(ID INT DEFAULT 0 NOT NULL))
1634:                    int backup = parseIndex;
1635:                    boolean not = false;
1636:                    if (readIf("NOT")) {
1637:                        not = true;
1638:                        if (isToken("NULL")) {
1639:                            // this really only works for NOT NULL!
1640:                            parseIndex = backup;
1641:                            currentToken = "NOT";
1642:                            break;
1643:                        }
1644:                    }
1645:                    if (readIf("LIKE")) {
1646:                        Expression b = readConcat();
1647:                        Expression esc = null;
1648:                        if (readIf("ESCAPE")) {
1649:                            esc = readConcat();
1650:                        }
1651:                        recompileAlways = true;
1652:                        r = new CompareLike(database.getCompareMode(), r, b,
1653:                                esc, false);
1654:                    } else if (readIf("REGEXP")) {
1655:                        Expression b = readConcat();
1656:                        r = new CompareLike(database.getCompareMode(), r, b,
1657:                                null, true);
1658:                    } else if (readIf("IS")) {
1659:                        int type;
1660:                        if (readIf("NOT")) {
1661:                            type = Comparison.IS_NOT_NULL;
1662:                        } else {
1663:                            type = Comparison.IS_NULL;
1664:                        }
1665:                        read("NULL");
1666:                        r = new Comparison(session, type, r, null);
1667:                    } else if (readIf("IN")) {
1668:                        if (SysProperties.OPTIMIZE_IN) {
1669:                            recompileAlways = true;
1670:                        }
1671:                        read("(");
1672:                        if (readIf(")")) {
1673:                            r = ValueExpression.get(ValueBoolean.get(false));
1674:                        } else {
1675:                            if (isToken("SELECT") || isToken("FROM")) {
1676:                                Query query = parseSelect();
1677:                                r = new ConditionInSelect(database, r, query,
1678:                                        false, Comparison.EQUAL);
1679:                            } else {
1680:                                ObjectArray v = new ObjectArray();
1681:                                Expression last;
1682:                                do {
1683:                                    last = readExpression();
1684:                                    v.add(last);
1685:                                } while (readIf(","));
1686:                                if (v.size() == 1 && (last instanceof  Subquery)) {
1687:                                    Subquery s = (Subquery) last;
1688:                                    Query q = s.getQuery();
1689:                                    r = new ConditionInSelect(database, r, q,
1690:                                            false, Comparison.EQUAL);
1691:                                } else {
1692:                                    r = new ConditionIn(database, r, v);
1693:                                }
1694:                            }
1695:                            read(")");
1696:                        }
1697:                    } else if (readIf("BETWEEN")) {
1698:                        Expression low = readConcat();
1699:                        read("AND");
1700:                        Expression high = readConcat();
1701:                        Expression condLow = new Comparison(session,
1702:                                Comparison.SMALLER_EQUAL, low, r);
1703:                        Expression condHigh = new Comparison(session,
1704:                                Comparison.BIGGER_EQUAL, high, r);
1705:                        r = new ConditionAndOr(ConditionAndOr.AND, condLow,
1706:                                condHigh);
1707:                    } else {
1708:                        // TODO parser: if we use a switch case, we don't need
1709:                        // getCompareType any more
1710:                        int compareType = getCompareType(currentTokenType);
1711:                        if (compareType < 0) {
1712:                            break;
1713:                        }
1714:                        read();
1715:                        if (readIf("ALL")) {
1716:                            read("(");
1717:                            Query query = parseSelect();
1718:                            r = new ConditionInSelect(database, r, query, true,
1719:                                    compareType);
1720:                            read(")");
1721:                        } else if (readIf("ANY") || readIf("SOME")) {
1722:                            read("(");
1723:                            Query query = parseSelect();
1724:                            r = new ConditionInSelect(database, r, query,
1725:                                    false, compareType);
1726:                            read(")");
1727:                        } else {
1728:                            Expression right = readConcat();
1729:                            if (readIf("(") && readIf("+") && readIf(")")) {
1730:                                // support for a subset of old-fashioned Oracle outer
1731:                                // join with (+)
1732:                                if (r instanceof  ExpressionColumn
1733:                                        && right instanceof  ExpressionColumn) {
1734:                                    ExpressionColumn leftCol = (ExpressionColumn) r;
1735:                                    ExpressionColumn rightCol = (ExpressionColumn) right;
1736:                                    ObjectArray filters = currentSelect
1737:                                            .getTopFilters();
1738:                                    for (int i = 0; filters != null
1739:                                            && i < filters.size(); i++) {
1740:                                        TableFilter f = (TableFilter) filters
1741:                                                .get(i);
1742:                                        leftCol.mapColumns(f, 0);
1743:                                        rightCol.mapColumns(f, 0);
1744:                                    }
1745:                                    TableFilter leftFilter = leftCol
1746:                                            .getTableFilter();
1747:                                    TableFilter rightFilter = rightCol
1748:                                            .getTableFilter();
1749:                                    r = new Comparison(session, compareType, r,
1750:                                            right);
1751:                                    if (leftFilter != null
1752:                                            && rightFilter != null) {
1753:                                        filters.remove(filters
1754:                                                .indexOf(rightFilter));
1755:                                        leftFilter
1756:                                                .addJoin(rightFilter, true, r);
1757:                                        r = ValueExpression.get(ValueBoolean
1758:                                                .get(true));
1759:                                    }
1760:                                }
1761:                            } else {
1762:                                r = new Comparison(session, compareType, r,
1763:                                        right);
1764:                            }
1765:                        }
1766:                    }
1767:                    if (not) {
1768:                        r = new ConditionNot(r);
1769:                    }
1770:                }
1771:                return r;
1772:            }
1773:
1774:            private Expression readConcat() throws SQLException {
1775:                Expression r = readSum();
1776:                while (true) {
1777:                    if (readIf("||")) {
1778:                        r = new Operation(Operation.CONCAT, r, readSum());
1779:                    } else if (readIf("~")) {
1780:                        if (readIf("*")) {
1781:                            Function function = Function.getFunction(database,
1782:                                    "CAST");
1783:                            function.setDataType(new Column("X",
1784:                                    Value.STRING_IGNORECASE));
1785:                            function.setParameter(0, r);
1786:                            r = function;
1787:                        }
1788:                        r = new CompareLike(database.getCompareMode(), r,
1789:                                readSum(), null, true);
1790:                    } else if (readIf("!~")) {
1791:                        if (readIf("*")) {
1792:                            Function function = Function.getFunction(database,
1793:                                    "CAST");
1794:                            function.setDataType(new Column("X",
1795:                                    Value.STRING_IGNORECASE));
1796:                            function.setParameter(0, r);
1797:                            r = function;
1798:                        }
1799:                        r = new ConditionNot(new CompareLike(database
1800:                                .getCompareMode(), r, readSum(), null, true));
1801:                    } else {
1802:                        return r;
1803:                    }
1804:                }
1805:            }
1806:
1807:            private Expression readSum() throws SQLException {
1808:                Expression r = readFactor();
1809:                while (true) {
1810:                    if (readIf("+")) {
1811:                        r = new Operation(Operation.PLUS, r, readFactor());
1812:                    } else if (readIf("-")) {
1813:                        r = new Operation(Operation.MINUS, r, readFactor());
1814:                    } else {
1815:                        return r;
1816:                    }
1817:                }
1818:            }
1819:
1820:            private Expression readFactor() throws SQLException {
1821:                Expression r = readTerm();
1822:                while (true) {
1823:                    if (readIf("*")) {
1824:                        r = new Operation(Operation.MULTIPLY, r, readTerm());
1825:                    } else if (readIf("/")) {
1826:                        r = new Operation(Operation.DIVIDE, r, readTerm());
1827:                    } else {
1828:                        return r;
1829:                    }
1830:                }
1831:            }
1832:
1833:            private Expression readAggregate(int aggregateType)
1834:                    throws SQLException {
1835:                if (currentSelect == null) {
1836:                    throw getSyntaxError();
1837:                }
1838:                currentSelect.setGroupQuery();
1839:                Expression r;
1840:                if (aggregateType == Aggregate.COUNT) {
1841:                    if (readIf("*")) {
1842:                        r = new Aggregate(database, Aggregate.COUNT_ALL, null,
1843:                                currentSelect, false);
1844:                    } else {
1845:                        boolean distinct = readIf("DISTINCT");
1846:                        Expression on = readExpression();
1847:                        if (on instanceof  Wildcard && !distinct) {
1848:                            // PostgreSQL compatibility: count(t.*)
1849:                            r = new Aggregate(database, Aggregate.COUNT_ALL,
1850:                                    null, currentSelect, false);
1851:                        } else {
1852:                            r = new Aggregate(database, Aggregate.COUNT, on,
1853:                                    currentSelect, distinct);
1854:                        }
1855:                    }
1856:                } else if (aggregateType == Aggregate.GROUP_CONCAT) {
1857:                    boolean distinct = readIf("DISTINCT");
1858:                    Aggregate agg = new Aggregate(database,
1859:                            Aggregate.GROUP_CONCAT, readExpression(),
1860:                            currentSelect, distinct);
1861:                    if (readIf("ORDER")) {
1862:                        read("BY");
1863:                        agg.setOrder(parseSimpleOrderList());
1864:                    }
1865:                    if (readIf("SEPARATOR")) {
1866:                        agg.setSeparator(readExpression());
1867:                    }
1868:                    r = agg;
1869:                } else {
1870:                    boolean distinct = readIf("DISTINCT");
1871:                    r = new Aggregate(database, aggregateType,
1872:                            readExpression(), currentSelect, distinct);
1873:                }
1874:                read(")");
1875:                return r;
1876:            }
1877:
1878:            private ObjectArray parseSimpleOrderList() throws SQLException {
1879:                ObjectArray orderList = new ObjectArray();
1880:                do {
1881:                    SelectOrderBy order = new SelectOrderBy();
1882:                    Expression expr = readExpression();
1883:                    order.expression = expr;
1884:                    if (readIf("DESC")) {
1885:                        order.descending = true;
1886:                    } else {
1887:                        readIf("ASC");
1888:                    }
1889:                    orderList.add(order);
1890:                } while (readIf(","));
1891:                return orderList;
1892:            }
1893:
1894:            private JavaFunction readJavaFunction(String name)
1895:                    throws SQLException {
1896:                FunctionAlias functionAlias = database.findFunctionAlias(name);
1897:                if (functionAlias == null) {
1898:                    // TODO compatibility: support 'on the fly java functions' as HSQLDB
1899:                    // ( CALL "java.lang.Math.sqrt"(2.0) )
1900:                    throw Message.getSQLException(
1901:                            ErrorCode.FUNCTION_NOT_FOUND_1, name);
1902:                }
1903:                int paramCount = functionAlias.getParameterCount();
1904:                Expression[] args = new Expression[paramCount];
1905:                for (int i = 0; i < args.length; i++) {
1906:                    if (i > 0) {
1907:                        read(",");
1908:                    }
1909:                    args[i] = readExpression();
1910:                }
1911:                read(")");
1912:                JavaFunction func = new JavaFunction(functionAlias, args);
1913:                return func;
1914:            }
1915:
1916:            private JavaAggregate readJavaAggregate(UserAggregate aggregate)
1917:                    throws SQLException {
1918:                ObjectArray params = new ObjectArray();
1919:                do {
1920:                    params.add(readExpression());
1921:                } while (readIf(","));
1922:                read(")");
1923:                Expression[] list = new Expression[params.size()];
1924:                params.toArray(list);
1925:                JavaAggregate agg = new JavaAggregate(aggregate, list,
1926:                        currentSelect);
1927:                currentSelect.setGroupQuery();
1928:                return agg;
1929:            }
1930:
1931:            private Expression readFunction(String name) throws SQLException {
1932:                int agg = Aggregate.getAggregateType(name);
1933:                if (agg >= 0) {
1934:                    return readAggregate(agg);
1935:                }
1936:                Function function = Function.getFunction(database, name);
1937:                if (function == null) {
1938:                    UserAggregate aggregate = database.findAggregate(name);
1939:                    if (aggregate != null) {
1940:                        return readJavaAggregate(aggregate);
1941:                    }
1942:                    return readJavaFunction(name);
1943:                }
1944:                switch (function.getFunctionType()) {
1945:                case Function.CAST: {
1946:                    function.setParameter(0, readExpression());
1947:                    read("AS");
1948:                    Column type = parseColumn(null);
1949:                    function.setDataType(type);
1950:                    read(")");
1951:                    break;
1952:                }
1953:                case Function.CONVERT: {
1954:                    function.setParameter(0, readExpression());
1955:                    read(",");
1956:                    Column type = parseColumn(null);
1957:                    function.setDataType(type);
1958:                    read(")");
1959:                    break;
1960:                }
1961:                case Function.EXTRACT: {
1962:                    function.setParameter(0, ValueExpression.get(ValueString
1963:                            .get(currentToken)));
1964:                    read();
1965:                    read("FROM");
1966:                    function.setParameter(1, readExpression());
1967:                    read(")");
1968:                    break;
1969:                }
1970:                case Function.SUBSTRING: {
1971:                    function.setParameter(0, readExpression());
1972:                    if (!readIf(",")) {
1973:                        read("FROM");
1974:                    }
1975:                    function.setParameter(1, readExpression());
1976:                    if (readIf("FOR") || readIf(",")) {
1977:                        function.setParameter(2, readExpression());
1978:                    }
1979:                    read(")");
1980:                    break;
1981:                }
1982:                case Function.POSITION: {
1983:                    // can't read expression because IN would be read too early
1984:                    function.setParameter(0, readConcat());
1985:                    if (!readIf(",")) {
1986:                        read("IN");
1987:                    }
1988:                    function.setParameter(1, readExpression());
1989:                    read(")");
1990:                    break;
1991:                }
1992:                case Function.TRIM: {
1993:                    Expression space = null;
1994:                    if (readIf("LEADING")) {
1995:                        function = Function.getFunction(database, "LTRIM");
1996:                        if (!readIf("FROM")) {
1997:                            space = readExpression();
1998:                            read("FROM");
1999:                        }
2000:                    } else if (readIf("TRAILING")) {
2001:                        function = Function.getFunction(database, "RTRIM");
2002:                        if (!readIf("FROM")) {
2003:                            space = readExpression();
2004:                            read("FROM");
2005:                        }
2006:                    } else if (readIf("BOTH")) {
2007:                        if (!readIf("FROM")) {
2008:                            space = readExpression();
2009:                            read("FROM");
2010:                        }
2011:                    }
2012:                    Expression p0 = readExpression();
2013:                    if (readIf(",")) {
2014:                        space = readExpression();
2015:                    } else if (readIf("FROM")) {
2016:                        space = p0;
2017:                        p0 = readExpression();
2018:                    }
2019:                    function.setParameter(0, p0);
2020:                    if (space != null) {
2021:                        function.setParameter(1, space);
2022:                    }
2023:                    read(")");
2024:                    break;
2025:                }
2026:                case Function.TABLE:
2027:                case Function.TABLE_DISTINCT: {
2028:                    int i = 0;
2029:                    ObjectArray columns = new ObjectArray();
2030:                    do {
2031:                        String columnName = readAliasIdentifier();
2032:                        Column column = parseColumn(columnName);
2033:                        columns.add(column);
2034:                        read("=");
2035:                        function.setParameter(i, readExpression());
2036:                        i++;
2037:                    } while (readIf(","));
2038:                    read(")");
2039:                    TableFunction tf = (TableFunction) function;
2040:                    tf.setColumns(columns);
2041:                    break;
2042:                }
2043:                default:
2044:                    if (!readIf(")")) {
2045:                        int i = 0;
2046:                        do {
2047:                            function.setParameter(i++, readExpression());
2048:                        } while (readIf(","));
2049:                        read(")");
2050:                    }
2051:                }
2052:                function.doneWithParameters();
2053:                return function;
2054:            }
2055:
2056:            private Function readFunctionWithoutParameters(String name)
2057:                    throws SQLException {
2058:                if (readIf("(")) {
2059:                    read(")");
2060:                }
2061:                Function function = Function.getFunction(database, name);
2062:                function.doneWithParameters();
2063:                return function;
2064:            }
2065:
2066:            private Expression readWildcardOrSequenceValue(String schemaName,
2067:                    String objectName) throws SQLException {
2068:                if (readIf("*")) {
2069:                    return new Wildcard(schemaName, objectName);
2070:                }
2071:                if (schemaName == null) {
2072:                    schemaName = session.getCurrentSchemaName();
2073:                }
2074:                if (readIf("NEXTVAL")) {
2075:                    Sequence sequence = database.getSchema(schemaName)
2076:                            .findSequence(objectName);
2077:                    if (sequence != null) {
2078:                        return new SequenceValue(sequence);
2079:                    }
2080:                } else if (readIf("CURRVAL")) {
2081:                    Sequence sequence = database.getSchema(schemaName)
2082:                            .findSequence(objectName);
2083:                    if (sequence != null) {
2084:                        Function function = Function.getFunction(database,
2085:                                "CURRVAL");
2086:                        function.setParameter(0, ValueExpression
2087:                                .get(ValueString.get(schemaName)));
2088:                        function.setParameter(1, ValueExpression
2089:                                .get(ValueString.get(objectName)));
2090:                        function.doneWithParameters();
2091:                        return function;
2092:                    }
2093:                }
2094:                return null;
2095:            }
2096:
2097:            private Expression readTermObjectDot(String objectName)
2098:                    throws SQLException {
2099:                Expression expr = readWildcardOrSequenceValue(null, objectName);
2100:                if (expr != null) {
2101:                    return expr;
2102:                }
2103:                String name = readColumnIdentifier();
2104:                if (readIf(".")) {
2105:                    String schemaName = objectName;
2106:                    objectName = name;
2107:                    expr = readWildcardOrSequenceValue(schemaName, objectName);
2108:                    if (expr != null) {
2109:                        return expr;
2110:                    }
2111:                    name = readColumnIdentifier();
2112:                    if (readIf(".")) {
2113:                        String databaseName = schemaName;
2114:                        if (!database.getShortName().equals(databaseName)) {
2115:                            throw Message.getSQLException(
2116:                                    ErrorCode.DATABASE_NOT_FOUND_1,
2117:                                    databaseName);
2118:                        }
2119:                        schemaName = objectName;
2120:                        objectName = name;
2121:                        expr = readWildcardOrSequenceValue(schemaName,
2122:                                objectName);
2123:                        if (expr != null) {
2124:                            return expr;
2125:                        }
2126:                        name = readColumnIdentifier();
2127:                        return new ExpressionColumn(database, schemaName,
2128:                                objectName, name);
2129:                    }
2130:                    return new ExpressionColumn(database, schemaName,
2131:                            objectName, name);
2132:                }
2133:                return new ExpressionColumn(database, null, objectName, name);
2134:            }
2135:
2136:            private Expression readTerm() throws SQLException {
2137:                Expression r;
2138:                switch (currentTokenType) {
2139:                case AT:
2140:                    read();
2141:                    r = new Variable(session, readAliasIdentifier());
2142:                    break;
2143:                case PARAMETER:
2144:                    // there must be no space between ? and the number
2145:                    boolean indexed = Character
2146:                            .isDigit(sqlCommandChars[parseIndex]);
2147:                    read();
2148:                    if (indexed && currentTokenType == VALUE
2149:                            && currentValue.getType() == Value.INT) {
2150:                        if (indexedParameterList == null) {
2151:                            if (parameters == null) {
2152:                                // this can occur when parsing expressions only (for example check constraints)
2153:                                throw getSyntaxError();
2154:                            } else if (parameters.size() > 0) {
2155:                                throw Message
2156:                                        .getSQLException(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
2157:                            }
2158:                            indexedParameterList = new ObjectArray();
2159:                        }
2160:                        int index = currentValue.getInt() - 1;
2161:                        if (index < 0 || index >= Constants.MAX_PARAMETER_INDEX) {
2162:                            throw Message.getInvalidValueException("" + index,
2163:                                    "Parameter Index");
2164:                        }
2165:                        if (indexedParameterList.size() <= index) {
2166:                            indexedParameterList.setSize(index + 1);
2167:                        }
2168:                        r = (Parameter) indexedParameterList.get(index);
2169:                        if (r == null) {
2170:                            r = new Parameter(index);
2171:                            indexedParameterList.set(index, r);
2172:                        }
2173:                        read();
2174:                    } else {
2175:                        if (indexedParameterList != null) {
2176:                            throw Message
2177:                                    .getSQLException(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
2178:                        }
2179:                        r = new Parameter(parameters.size());
2180:                    }
2181:                    parameters.add(r);
2182:                    break;
2183:                case KEYWORD:
2184:                    if (isToken("SELECT") || isToken("FROM")) {
2185:                        Query query = parseSelect();
2186:                        r = new Subquery(query);
2187:                    } else {
2188:                        throw getSyntaxError();
2189:                    }
2190:                    break;
2191:                case IDENTIFIER:
2192:                    String name = currentToken;
2193:                    if (currentTokenQuoted) {
2194:                        read();
2195:                        if (readIf("(")) {
2196:                            r = readFunction(name);
2197:                        } else if (readIf(".")) {
2198:                            r = readTermObjectDot(name);
2199:                        } else {
2200:                            r = new ExpressionColumn(database, null, null, name);
2201:                        }
2202:                    } else {
2203:                        read();
2204:                        if ("X".equals(name) && currentTokenType == VALUE
2205:                                && currentValue.getType() == Value.STRING) {
2206:                            read();
2207:                            byte[] buffer = ByteUtils
2208:                                    .convertStringToBytes(currentValue
2209:                                            .getString());
2210:                            r = ValueExpression.get(ValueBytes
2211:                                    .getNoCopy(buffer));
2212:                        } else if (readIf(".")) {
2213:                            r = readTermObjectDot(name);
2214:                        } else if ("CASE".equals(name)) {
2215:                            // CASE must be processed before (,
2216:                            // otherwise CASE(3) would be a function call, which it is
2217:                            // not
2218:                            if (isToken("WHEN")) {
2219:                                r = readWhen(null);
2220:                            } else {
2221:                                Expression left = readExpression();
2222:                                r = readWhen(left);
2223:                            }
2224:                        } else if (readIf("(")) {
2225:                            r = readFunction(name);
2226:                        } else if ("CURRENT_USER".equals(name)) {
2227:                            r = readFunctionWithoutParameters("USER");
2228:                        } else if ("CURRENT".equals(name)) {
2229:                            if (readIf("TIMESTAMP")) {
2230:                                r = readFunctionWithoutParameters("CURRENT_TIMESTAMP");
2231:                            } else if (readIf("TIME")) {
2232:                                r = readFunctionWithoutParameters("CURRENT_TIME");
2233:                            } else if (readIf("DATE")) {
2234:                                r = readFunctionWithoutParameters("CURRENT_DATE");
2235:                            } else {
2236:                                r = new ExpressionColumn(database, null, null,
2237:                                        name);
2238:                            }
2239:                        } else if ("NEXT".equals(name) && readIf("VALUE")) {
2240:                            read("FOR");
2241:                            Sequence sequence = readSequence();
2242:                            r = new SequenceValue(sequence);
2243:                        } else if ("DATE".equals(name)
2244:                                && currentTokenType == VALUE
2245:                                && currentValue.getType() == Value.STRING) {
2246:                            String date = currentValue.getString();
2247:                            read();
2248:                            r = ValueExpression.get(ValueDate.get(ValueDate
2249:                                    .parseDate(date)));
2250:                        } else if ("TIME".equals(name)
2251:                                && currentTokenType == VALUE
2252:                                && currentValue.getType() == Value.STRING) {
2253:                            String time = currentValue.getString();
2254:                            read();
2255:                            r = ValueExpression.get(ValueTime.get(ValueTime
2256:                                    .parseTime(time)));
2257:                        } else if ("TIMESTAMP".equals(name)
2258:                                && currentTokenType == VALUE
2259:                                && currentValue.getType() == Value.STRING) {
2260:                            String timestamp = currentValue.getString();
2261:                            read();
2262:                            r = ValueExpression.get(ValueTimestamp
2263:                                    .getNoCopy(ValueTimestamp
2264:                                            .parseTimestamp(timestamp)));
2265:                        } else if ("E".equals(name)
2266:                                && currentTokenType == VALUE
2267:                                && currentValue.getType() == Value.STRING) {
2268:                            String text = currentValue.getString();
2269:                            read();
2270:                            r = ValueExpression.get(ValueString.get(text));
2271:                        } else {
2272:                            r = new ExpressionColumn(database, null, null, name);
2273:                        }
2274:                    }
2275:                    break;
2276:                case MINUS:
2277:                    read();
2278:                    if (currentTokenType == VALUE) {
2279:                        r = ValueExpression.get(currentValue.negate());
2280:                        // convert Integer.MIN_VALUE to int (-Integer.MIN_VALUE needed
2281:                        // to be a long)
2282:                        if (r.getType() == Value.LONG
2283:                                && r.getValue(session).getLong() == Integer.MIN_VALUE) {
2284:                            r = ValueExpression.get(ValueInt
2285:                                    .get(Integer.MIN_VALUE));
2286:                        }
2287:                        read();
2288:                    } else {
2289:                        r = new Operation(Operation.NEGATE, readTerm(), null);
2290:                    }
2291:                    break;
2292:                case PLUS:
2293:                    read();
2294:                    r = readTerm();
2295:                    break;
2296:                case OPEN:
2297:                    read();
2298:                    r = readExpression();
2299:                    if (readIf(",")) {
2300:                        ObjectArray list = new ObjectArray();
2301:                        list.add(r);
2302:                        do {
2303:                            r = readExpression();
2304:                            list.add(r);
2305:                        } while (readIf(","));
2306:                        Expression[] array = new Expression[list.size()];
2307:                        list.toArray(array);
2308:                        r = new ExpressionList(array);
2309:                    }
2310:                    read(")");
2311:                    break;
2312:                case TRUE:
2313:                    read();
2314:                    r = ValueExpression.get(ValueBoolean.get(true));
2315:                    break;
2316:                case FALSE:
2317:                    read();
2318:                    r = ValueExpression.get(ValueBoolean.get(false));
2319:                    break;
2320:                case CURRENT_TIME:
2321:                    read();
2322:                    r = readFunctionWithoutParameters("CURRENT_TIME");
2323:                    break;
2324:                case CURRENT_DATE:
2325:                    read();
2326:                    r = readFunctionWithoutParameters("CURRENT_DATE");
2327:                    break;
2328:                case CURRENT_TIMESTAMP: {
2329:                    Function function = Function.getFunction(database,
2330:                            "CURRENT_TIMESTAMP");
2331:                    read();
2332:                    if (readIf("(")) {
2333:                        if (!readIf(")")) {
2334:                            function.setParameter(0, readExpression());
2335:                            read(")");
2336:                        }
2337:                    }
2338:                    function.doneWithParameters();
2339:                    r = function;
2340:                    break;
2341:                }
2342:                case ROWNUM:
2343:                    read();
2344:                    if (readIf("(")) {
2345:                        read(")");
2346:                    }
2347:                    r = new Rownum(currentSelect == null ? currentPrepared
2348:                            : currentSelect);
2349:                    break;
2350:                case NULL:
2351:                    read();
2352:                    r = ValueExpression.NULL;
2353:                    break;
2354:                case VALUE:
2355:                    r = ValueExpression.get(currentValue);
2356:                    read();
2357:                    break;
2358:                default:
2359:                    throw getSyntaxError();
2360:                }
2361:                if (readIf("[")) {
2362:                    Function function = Function.getFunction(database,
2363:                            "ARRAY_GET");
2364:                    function.setParameter(0, r);
2365:                    r = readExpression();
2366:                    r = new Operation(Operation.PLUS, r, ValueExpression
2367:                            .get(ValueInt.get(1)));
2368:                    function.setParameter(1, r);
2369:                    r = function;
2370:                    read("]");
2371:                }
2372:                if (readIf("::")) {
2373:                    // PostgreSQL compatibility
2374:                    Column col = parseColumn(null);
2375:                    Function function = Function.getFunction(database, "CAST");
2376:                    function.setDataType(col);
2377:                    function.setParameter(0, r);
2378:                    r = function;
2379:                }
2380:                return r;
2381:            }
2382:
2383:            private Expression readWhen(Expression left) throws SQLException {
2384:                if (readIf("END")) {
2385:                    readIf("CASE");
2386:                    return ValueExpression.NULL;
2387:                }
2388:                if (readIf("ELSE")) {
2389:                    Expression elsePart = readExpression();
2390:                    read("END");
2391:                    readIf("CASE");
2392:                    return elsePart;
2393:                }
2394:                readIf("WHEN");
2395:                Expression when = readExpression();
2396:                if (left != null) {
2397:                    when = new Comparison(session, Comparison.EQUAL, left, when);
2398:                }
2399:                read("THEN");
2400:                Expression then = readExpression();
2401:                Expression elsePart = readWhen(left);
2402:                Function function = Function.getFunction(session.getDatabase(),
2403:                        "CASEWHEN");
2404:                function.setParameter(0, when);
2405:                function.setParameter(1, then);
2406:                function.setParameter(2, elsePart);
2407:                function.doneWithParameters();
2408:                return function;
2409:            }
2410:
2411:            private int getPositiveInt() throws SQLException {
2412:                int v = getInt();
2413:                if (v < 0) {
2414:                    throw Message.getInvalidValueException("" + v,
2415:                            "positive integer");
2416:                }
2417:                return v;
2418:            }
2419:
2420:            private int getInt() throws SQLException {
2421:                boolean minus = false;
2422:                if (currentTokenType == MINUS) {
2423:                    minus = true;
2424:                    read();
2425:                } else if (currentTokenType == PLUS) {
2426:                    read();
2427:                }
2428:                if (currentTokenType != VALUE
2429:                        || currentValue.getType() != Value.INT) {
2430:                    throw Message.getSyntaxError(sqlCommand, parseIndex,
2431:                            "integer");
2432:                }
2433:                int i = currentValue.getInt();
2434:                read();
2435:                return minus ? -i : i;
2436:            }
2437:
2438:            private long readLong() throws SQLException {
2439:                boolean minus = false;
2440:                if (currentTokenType == MINUS) {
2441:                    minus = true;
2442:                    read();
2443:                }
2444:                if (currentTokenType != VALUE
2445:                        || (currentValue.getType() != Value.INT && currentValue
2446:                                .getType() != Value.DECIMAL)) {
2447:                    throw Message
2448:                            .getSyntaxError(sqlCommand, parseIndex, "long");
2449:                }
2450:                long i = currentValue.getLong();
2451:                read();
2452:                return minus ? -i : i;
2453:            }
2454:
2455:            private boolean readBooleanSetting() throws SQLException {
2456:                if (currentTokenType == VALUE) {
2457:                    boolean result = currentValue.getBoolean().booleanValue();
2458:                    read();
2459:                    return result;
2460:                }
2461:                if (readIf("TRUE") || readIf("ON")) {
2462:                    return true;
2463:                } else if (readIf("FALSE") || readIf("OFF")) {
2464:                    return false;
2465:                } else {
2466:                    throw getSyntaxError();
2467:                }
2468:            }
2469:
2470:            private String readString() throws SQLException {
2471:                Expression expr = readExpression().optimize(session);
2472:                if (!(expr instanceof  ValueExpression)) {
2473:                    throw Message.getSyntaxError(sqlCommand, parseIndex,
2474:                            "string");
2475:                }
2476:                String s = expr.getValue(session).getString();
2477:                return s;
2478:            }
2479:
2480:            private String readIdentifierWithSchema(String defaultSchemaName)
2481:                    throws SQLException {
2482:                if (currentTokenType != IDENTIFIER) {
2483:                    throw Message.getSyntaxError(sqlCommand, parseIndex,
2484:                            "identifier");
2485:                }
2486:                String s = currentToken;
2487:                read();
2488:                schemaName = defaultSchemaName;
2489:                if (readIf(".")) {
2490:                    schemaName = s;
2491:                    if (currentTokenType != IDENTIFIER) {
2492:                        throw Message.getSyntaxError(sqlCommand, parseIndex,
2493:                                "identifier");
2494:                    }
2495:                    s = currentToken;
2496:                    read();
2497:                }
2498:                if (".".equals(currentToken)) {
2499:                    if (schemaName.equalsIgnoreCase(database.getShortName())) {
2500:                        read(".");
2501:                        schemaName = s;
2502:                        if (currentTokenType != IDENTIFIER) {
2503:                            throw Message.getSyntaxError(sqlCommand,
2504:                                    parseIndex, "identifier");
2505:                        }
2506:                        s = currentToken;
2507:                        read();
2508:                    }
2509:                }
2510:                return s;
2511:            }
2512:
2513:            private String readIdentifierWithSchema() throws SQLException {
2514:                return readIdentifierWithSchema(session.getCurrentSchemaName());
2515:            }
2516:
2517:            private String readAliasIdentifier() throws SQLException {
2518:                return readColumnIdentifier();
2519:            }
2520:
2521:            private String readUniqueIdentifier() throws SQLException {
2522:                return readColumnIdentifier();
2523:            }
2524:
2525:            private String readColumnIdentifier() throws SQLException {
2526:                if (currentTokenType != IDENTIFIER) {
2527:                    throw Message.getSyntaxError(sqlCommand, parseIndex,
2528:                            "identifier");
2529:                }
2530:                String s = currentToken;
2531:                read();
2532:                return s;
2533:            }
2534:
2535:            private void read(String expected) throws SQLException {
2536:                if (!expected.equals(currentToken) || currentTokenQuoted) {
2537:                    throw Message.getSyntaxError(sqlCommand, parseIndex,
2538:                            expected);
2539:                }
2540:                read();
2541:            }
2542:
2543:            private boolean readIf(String token) throws SQLException {
2544:                if (token.equals(currentToken) && !currentTokenQuoted) {
2545:                    read();
2546:                    return true;
2547:                }
2548:                addExpected(token);
2549:                return false;
2550:            }
2551:
2552:            private boolean isToken(String token) {
2553:                boolean result = token.equals(currentToken)
2554:                        && !currentTokenQuoted;
2555:                if (result) {
2556:                    return true;
2557:                }
2558:                addExpected(token);
2559:                return false;
2560:            }
2561:
2562:            private void addExpected(String token) {
2563:                if (expected != null) {
2564:                    expected.add(token);
2565:                }
2566:            }
2567:
2568:            private void read() throws SQLException {
2569:                currentTokenQuoted = false;
2570:                if (expected != null) {
2571:                    expected.clear();
2572:                }
2573:                int[] types = characterTypes;
2574:                lastParseIndex = parseIndex;
2575:                int i = parseIndex;
2576:                int type = types[i];
2577:                while (type == 0) {
2578:                    type = types[++i];
2579:                }
2580:                int start = i;
2581:                char[] chars = sqlCommandChars;
2582:                char c = chars[i++];
2583:                currentToken = "";
2584:                switch (type) {
2585:                case CHAR_NAME:
2586:                    while (true) {
2587:                        type = types[i];
2588:                        if (type != CHAR_NAME && type != CHAR_VALUE) {
2589:                            c = chars[i];
2590:                            break;
2591:                        }
2592:                        i++;
2593:                    }
2594:                    currentToken = StringCache.getNew(sqlCommand.substring(
2595:                            start, i));
2596:                    currentTokenType = getTokenType(currentToken);
2597:                    parseIndex = i;
2598:                    return;
2599:                case CHAR_QUOTED: {
2600:                    String result = null;
2601:                    while (true) {
2602:                        for (int begin = i;; i++) {
2603:                            if (chars[i] == '\"') {
2604:                                if (result == null) {
2605:                                    result = sqlCommand.substring(begin, i);
2606:                                } else {
2607:                                    result += sqlCommand
2608:                                            .substring(begin - 1, i);
2609:                                }
2610:                                break;
2611:                            }
2612:                        }
2613:                        if (chars[++i] != '\"') {
2614:                            break;
2615:                        }
2616:                        i++;
2617:                    }
2618:                    currentToken = StringCache.getNew(result);
2619:                    parseIndex = i;
2620:                    currentTokenQuoted = true;
2621:                    currentTokenType = IDENTIFIER;
2622:                    return;
2623:                }
2624:                case CHAR_SPECIAL_2:
2625:                    if (types[i] == CHAR_SPECIAL_2) {
2626:                        i++;
2627:                    }
2628:                    currentToken = sqlCommand.substring(start, i);
2629:                    currentTokenType = getSpecialType(currentToken);
2630:                    parseIndex = i;
2631:                    return;
2632:                case CHAR_SPECIAL_1:
2633:                    currentToken = sqlCommand.substring(start, i);
2634:                    currentTokenType = getSpecialType(currentToken);
2635:                    parseIndex = i;
2636:                    return;
2637:                case CHAR_VALUE:
2638:                    if (c == '0' && chars[i] == 'X') {
2639:                        // hex number
2640:                        long number = 0;
2641:                        start += 2;
2642:                        i++;
2643:                        while (true) {
2644:                            c = chars[i];
2645:                            if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) {
2646:                                checkLiterals(false);
2647:                                currentValue = ValueInt.get((int) number);
2648:                                currentTokenType = VALUE;
2649:                                currentToken = "0";
2650:                                parseIndex = i;
2651:                                return;
2652:                            }
2653:                            number = (number << 4) + c
2654:                                    - (c >= 'A' ? ('A' - 0xa) : ('0'));
2655:                            if (number > Integer.MAX_VALUE) {
2656:                                readHexDecimal(start, i);
2657:                                return;
2658:                            }
2659:                            i++;
2660:                        }
2661:                    }
2662:                    long number = c - '0';
2663:                    while (true) {
2664:                        c = chars[i];
2665:                        if (c < '0' || c > '9') {
2666:                            if (c == '.') {
2667:                                readDecimal(start, i);
2668:                                break;
2669:                            }
2670:                            if (c == 'E') {
2671:                                readDecimal(start, i);
2672:                                break;
2673:                            }
2674:                            checkLiterals(false);
2675:                            currentValue = ValueInt.get((int) number);
2676:                            currentTokenType = VALUE;
2677:                            currentToken = "0";
2678:                            parseIndex = i;
2679:                            break;
2680:                        }
2681:                        number = number * 10 + (c - '0');
2682:                        if (number > Integer.MAX_VALUE) {
2683:                            readDecimal(start, i);
2684:                            break;
2685:                        }
2686:                        i++;
2687:                    }
2688:                    return;
2689:                case CHAR_DECIMAL:
2690:                    if (types[i] != CHAR_VALUE) {
2691:                        currentTokenType = KEYWORD;
2692:                        currentToken = ".";
2693:                        parseIndex = i;
2694:                        return;
2695:                    }
2696:                    readDecimal(i - 1, i);
2697:                    return;
2698:                case CHAR_STRING: {
2699:                    String result = null;
2700:                    while (true) {
2701:                        for (int begin = i;; i++) {
2702:                            if (chars[i] == '\'') {
2703:                                if (result == null) {
2704:                                    result = sqlCommand.substring(begin, i);
2705:                                } else {
2706:                                    result += sqlCommand
2707:                                            .substring(begin - 1, i);
2708:                                }
2709:                                break;
2710:                            }
2711:                        }
2712:                        if (chars[++i] != '\'') {
2713:                            break;
2714:                        }
2715:                        i++;
2716:                    }
2717:                    currentToken = "'";
2718:                    checkLiterals(false);
2719:                    currentValue = ValueString.get(StringCache.getNew(result));
2720:                    parseIndex = i;
2721:                    currentTokenType = VALUE;
2722:                    return;
2723:                }
2724:                case CHAR_END:
2725:                    currentToken = "";
2726:                    currentTokenType = END;
2727:                    parseIndex = i;
2728:                    return;
2729:                default:
2730:                    throw getSyntaxError();
2731:                }
2732:            }
2733:
2734:            private void checkLiterals(boolean text) throws SQLException {
2735:                if (!session.getAllowLiterals()) {
2736:                    int allowed = database.getAllowLiterals();
2737:                    if (allowed == Constants.ALLOW_LITERALS_NONE
2738:                            || (text && allowed != Constants.ALLOW_LITERALS_ALL)) {
2739:                        throw Message
2740:                                .getSQLException(ErrorCode.LITERALS_ARE_NOT_ALLOWED);
2741:                    }
2742:                }
2743:            }
2744:
2745:            private void readHexDecimal(int start, int i) throws SQLException {
2746:                char[] chars = sqlCommandChars;
2747:                char c;
2748:                do {
2749:                    c = chars[++i];
2750:                } while ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'));
2751:                parseIndex = i;
2752:                String sub = sqlCommand.substring(start, i);
2753:                BigDecimal bd = new BigDecimal(new BigInteger(sub, 16));
2754:                checkLiterals(false);
2755:                currentValue = ValueDecimal.get(bd);
2756:                currentTokenType = VALUE;
2757:            }
2758:
2759:            private void readDecimal(int start, int i) throws SQLException {
2760:                char[] chars = sqlCommandChars;
2761:                int[] types = characterTypes;
2762:                // go until the first non-number
2763:                while (true) {
2764:                    int t = types[i];
2765:                    if (t != CHAR_DECIMAL && t != CHAR_VALUE) {
2766:                        break;
2767:                    }
2768:                    i++;
2769:                }
2770:                if (chars[i] == 'E') {
2771:                    i++;
2772:                    if (chars[i] == '+' || chars[i] == '-') {
2773:                        i++;
2774:                    }
2775:                    if (types[i] != CHAR_VALUE) {
2776:                        throw getSyntaxError();
2777:                    }
2778:                    while (types[++i] == CHAR_VALUE) {
2779:                        // go until the first non-number
2780:                    }
2781:                }
2782:                parseIndex = i;
2783:                String sub = sqlCommand.substring(start, i);
2784:                BigDecimal bd;
2785:                try {
2786:                    bd = new BigDecimal(sub);
2787:                } catch (NumberFormatException e) {
2788:                    throw Message.getSQLException(
2789:                            ErrorCode.DATA_CONVERSION_ERROR_1,
2790:                            new String[] { sub }, e);
2791:                }
2792:                checkLiterals(false);
2793:                currentValue = ValueDecimal.get(bd);
2794:                currentTokenType = VALUE;
2795:            }
2796:
2797:            public String getOriginalSQL() {
2798:                return originalSQL;
2799:            }
2800:
2801:            public Session getSession() {
2802:                return session;
2803:            }
2804:
2805:            private void initialize(String sql) throws SQLException {
2806:                if (sql == null) {
2807:                    sql = "";
2808:                }
2809:                originalSQL = sql;
2810:                sqlCommand = sql;
2811:                int len = sql.length() + 1;
2812:                char[] command = new char[len];
2813:                int[] types = new int[len];
2814:                len--;
2815:                sql.getChars(0, len, command, 0);
2816:                boolean changed = false;
2817:                command[len] = ' ';
2818:                int startLoop = 0;
2819:                // TODO optimization in parser: could remember the length of each token
2820:                for (int i = 0; i < len; i++) {
2821:                    char c = command[i];
2822:                    int type = 0;
2823:                    switch (c) {
2824:                    case '/':
2825:                        if (command[i + 1] == '*') {
2826:                            // block comment
2827:                            changed = true;
2828:                            command[i] = ' ';
2829:                            command[i + 1] = ' ';
2830:                            startLoop = i;
2831:                            i += 2;
2832:                            checkRunOver(i, len, startLoop);
2833:                            while (command[i] != '*' || command[i + 1] != '/') {
2834:                                command[i++] = ' ';
2835:                                checkRunOver(i, len, startLoop);
2836:                            }
2837:                            command[i] = ' ';
2838:                            command[i + 1] = ' ';
2839:                            i++;
2840:                        } else if (command[i + 1] == '/') {
2841:                            // single line comment
2842:                            changed = true;
2843:                            startLoop = i;
2844:                            while (true) {
2845:                                c = command[i];
2846:                                if (c == '\n' || c == '\r' || i >= len - 1) {
2847:                                    break;
2848:                                }
2849:                                command[i++] = ' ';
2850:                                checkRunOver(i, len, startLoop);
2851:                            }
2852:                        } else {
2853:                            type = CHAR_SPECIAL_1;
2854:                        }
2855:                        break;
2856:                    case '-':
2857:                        if (command[i + 1] == '-') {
2858:                            // single line comment
2859:                            changed = true;
2860:                            startLoop = i;
2861:                            while (true) {
2862:                                c = command[i];
2863:                                if (c == '\n' || c == '\r' || i >= len - 1) {
2864:                                    break;
2865:                                }
2866:                                command[i++] = ' ';
2867:                                checkRunOver(i, len, startLoop);
2868:                            }
2869:                        } else {
2870:                            type = CHAR_SPECIAL_1;
2871:                        }
2872:                        break;
2873:                    case '(':
2874:                    case ')':
2875:                    case '{':
2876:                    case '}':
2877:                    case '*':
2878:                    case ',':
2879:                    case ';':
2880:                    case '+':
2881:                    case '%':
2882:                    case '?':
2883:                    case '@':
2884:                    case '$':
2885:                    case ']':
2886:                        type = CHAR_SPECIAL_1;
2887:                        break;
2888:                    case '!':
2889:                    case '<':
2890:                    case '>':
2891:                    case '|':
2892:                    case '=':
2893:                    case ':':
2894:                    case '~':
2895:                        type = CHAR_SPECIAL_2;
2896:                        break;
2897:                    case '.':
2898:                        type = CHAR_DECIMAL;
2899:                        break;
2900:                    case '\'':
2901:                        type = types[i] = CHAR_STRING;
2902:                        startLoop = i;
2903:                        while (command[++i] != '\'') {
2904:                            checkRunOver(i, len, startLoop);
2905:                        }
2906:                        break;
2907:                    case '[':
2908:                        if (database.getMode().squareBracketQuotedNames) {
2909:                            // SQL Server alias for "
2910:                            command[i] = '"';
2911:                            changed = true;
2912:                            type = types[i] = CHAR_QUOTED;
2913:                            startLoop = i;
2914:                            while (command[++i] != ']') {
2915:                                checkRunOver(i, len, startLoop);
2916:                            }
2917:                            command[i] = '"';
2918:                        } else {
2919:                            type = CHAR_SPECIAL_1;
2920:                        }
2921:                        break;
2922:                    case '`':
2923:                        // MySQL alias for ", but not case sensitive
2924:                        command[i] = '"';
2925:                        changed = true;
2926:                        type = types[i] = CHAR_QUOTED;
2927:                        startLoop = i;
2928:                        while (command[++i] != '`') {
2929:                            checkRunOver(i, len, startLoop);
2930:                            c = command[i];
2931:                            command[i] = Character.toUpperCase(c);
2932:                        }
2933:                        command[i] = '"';
2934:                        break;
2935:                    case '\"':
2936:                        type = types[i] = CHAR_QUOTED;
2937:                        startLoop = i;
2938:                        while (command[++i] != '\"') {
2939:                            checkRunOver(i, len, startLoop);
2940:                        }
2941:                        break;
2942:                    case '_':
2943:                        type = CHAR_NAME;
2944:                        break;
2945:                    default:
2946:                        if (c >= 'a' && c <= 'z') {
2947:                            command[i] = (char) (c - ('a' - 'A'));
2948:                            changed = true;
2949:                            type = CHAR_NAME;
2950:                        } else if (c >= 'A' && c <= 'Z') {
2951:                            type = CHAR_NAME;
2952:                        } else if (c >= '0' && c <= '9') {
2953:                            type = CHAR_VALUE;
2954:                        } else {
2955:                            // $ is not supported at this time (compatibility for
2956:                            // PostgreSQL: $1 )
2957:                            if (Character.isJavaIdentifierPart(c)) {
2958:                                type = CHAR_NAME;
2959:                                char u = Character.toUpperCase(c);
2960:                                if (u != c) {
2961:                                    command[i] = u;
2962:                                    changed = true;
2963:                                }
2964:                            }
2965:                        }
2966:                    }
2967:                    types[i] = (byte) type;
2968:                }
2969:                sqlCommandChars = command;
2970:                types[len] = CHAR_END;
2971:                characterTypes = types;
2972:                if (changed) {
2973:                    sqlCommand = new String(command);
2974:                }
2975:                parseIndex = 0;
2976:            }
2977:
2978:            private void checkRunOver(int i, int len, int startLoop)
2979:                    throws SQLException {
2980:                if (i >= len) {
2981:                    parseIndex = startLoop;
2982:                    throw getSyntaxError();
2983:                }
2984:            }
2985:
2986:            private int getSpecialType(String s) throws SQLException {
2987:                char c0 = s.charAt(0);
2988:                if (s.length() == 1) {
2989:                    switch (c0) {
2990:                    case '?':
2991:                    case '$':
2992:                        return PARAMETER;
2993:                    case '@':
2994:                        return AT;
2995:                    case '+':
2996:                        return PLUS;
2997:                    case '-':
2998:                        return MINUS;
2999:                    case '{':
3000:                    case '}':
3001:                    case '*':
3002:                    case '/':
3003:                    case ';':
3004:                    case ',':
3005:                    case ':':
3006:                    case '[':
3007:                    case ']':
3008:                    case '~':
3009:                        return KEYWORD;
3010:                    case '(':
3011:                        return OPEN;
3012:                    case ')':
3013:                        return CLOSE;
3014:                    case '<':
3015:                        return SMALLER;
3016:                    case '>':
3017:                        return BIGGER;
3018:                    case '=':
3019:                        return EQUAL;
3020:                    default:
3021:                        break;
3022:                    }
3023:                } else if (s.length() == 2) {
3024:                    switch (c0) {
3025:                    case ':':
3026:                        if ("::".equals(s)) {
3027:                            return KEYWORD;
3028:                        }
3029:                        break;
3030:                    case '>':
3031:                        if (">=".equals(s)) {
3032:                            return BIGGER_EQUAL;
3033:                        }
3034:                        break;
3035:                    case '<':
3036:                        if ("<=".equals(s)) {
3037:                            return SMALLER_EQUAL;
3038:                        } else if ("<>".equals(s)) {
3039:                            return NOT_EQUAL;
3040:                        }
3041:                        break;
3042:                    case '!':
3043:                        if ("!=".equals(s)) {
3044:                            return NOT_EQUAL;
3045:                        } else if ("!~".equals(s)) {
3046:                            return KEYWORD;
3047:                        }
3048:                        break;
3049:                    case '|':
3050:                        if ("||".equals(s)) {
3051:                            return STRING_CONCAT;
3052:                        }
3053:                        break;
3054:                    default:
3055:                    }
3056:                }
3057:                throw getSyntaxError();
3058:            }
3059:
3060:            private int getTokenType(String s) throws SQLException {
3061:                int len = s.length();
3062:                if (len == 0) {
3063:                    throw getSyntaxError();
3064:                }
3065:                return getSaveTokenType(s);
3066:            }
3067:
3068:            /**
3069:             * Checks if this string is a SQL keyword.
3070:             * 
3071:             * @param s the token to check
3072:             * @return true if it is a keyword
3073:             */
3074:            public static boolean isKeyword(String s) {
3075:                if (s == null || s.length() == 0) {
3076:                    return false;
3077:                }
3078:                return getSaveTokenType(s) != IDENTIFIER;
3079:            }
3080:
3081:            private static int getSaveTokenType(String s) {
3082:                switch (s.charAt(0)) {
3083:                case 'C':
3084:                    if (s.equals("CURRENT_TIMESTAMP")) {
3085:                        return CURRENT_TIMESTAMP;
3086:                    } else if (s.equals("CURRENT_TIME")) {
3087:                        return CURRENT_TIME;
3088:                    } else if (s.equals("CURRENT_DATE")) {
3089:                        return CURRENT_DATE;
3090:                    }
3091:                    return getKeywordOrIdentifier(s, "CROSS", KEYWORD);
3092:                case 'D':
3093:                    return getKeywordOrIdentifier(s, "DISTINCT", KEYWORD);
3094:                case 'E':
3095:                    if ("EXCEPT".equals(s)) {
3096:                        return KEYWORD;
3097:                    }
3098:                    return getKeywordOrIdentifier(s, "EXISTS", KEYWORD);
3099:                case 'F':
3100:                    if ("FROM".equals(s)) {
3101:                        return KEYWORD;
3102:                    } else if ("FOR".equals(s)) {
3103:                        return KEYWORD;
3104:                    } else if ("FULL".equals(s)) {
3105:                        return KEYWORD;
3106:                    }
3107:                    return getKeywordOrIdentifier(s, "FALSE", FALSE);
3108:                case 'G':
3109:                    return getKeywordOrIdentifier(s, "GROUP", KEYWORD);
3110:                case 'H':
3111:                    return getKeywordOrIdentifier(s, "HAVING", KEYWORD);
3112:                case 'I':
3113:                    if ("INNER".equals(s)) {
3114:                        return KEYWORD;
3115:                    } else if ("INTERSECT".equals(s)) {
3116:                        return KEYWORD;
3117:                    }
3118:                    return getKeywordOrIdentifier(s, "IS", KEYWORD);
3119:                case 'J':
3120:                    return getKeywordOrIdentifier(s, "JOIN", KEYWORD);
3121:                case 'L':
3122:                    if ("LIMIT".equals(s)) {
3123:                        return KEYWORD;
3124:                    }
3125:                    return getKeywordOrIdentifier(s, "LIKE", KEYWORD);
3126:                case 'M':
3127:                    return getKeywordOrIdentifier(s, "MINUS", KEYWORD);
3128:                case 'N':
3129:                    if ("NOT".equals(s)) {
3130:                        return KEYWORD;
3131:                    } else if ("NATURAL".equals(s)) {
3132:                        return KEYWORD;
3133:                    }
3134:                    return getKeywordOrIdentifier(s, "NULL", NULL);
3135:                case 'O':
3136:                    if ("ON".equals(s)) {
3137:                        return KEYWORD;
3138:                    }
3139:                    return getKeywordOrIdentifier(s, "ORDER", KEYWORD);
3140:                case 'P':
3141:                    return getKeywordOrIdentifier(s, "PRIMARY", KEYWORD);
3142:                case 'R':
3143:                    return getKeywordOrIdentifier(s, "ROWNUM", ROWNUM);
3144:                case 'S':
3145:                    if (s.equals("SYSTIMESTAMP")) {
3146:                        return CURRENT_TIMESTAMP;
3147:                    } else if (s.equals("SYSTIME")) {
3148:                        return CURRENT_TIME;
3149:                    } else if (s.equals("SYSDATE")) {
3150:                        return CURRENT_TIMESTAMP;
3151:                    }
3152:                    return getKeywordOrIdentifier(s, "SELECT", KEYWORD);
3153:                case 'T':
3154:                    if ("TODAY".equals(s)) {
3155:                        return CURRENT_DATE;
3156:                    }
3157:                    return getKeywordOrIdentifier(s, "TRUE", TRUE);
3158:                case 'U':
3159:                    return getKeywordOrIdentifier(s, "UNION", KEYWORD);
3160:                case 'W':
3161:                    return getKeywordOrIdentifier(s, "WHERE", KEYWORD);
3162:                default:
3163:                    return IDENTIFIER;
3164:                }
3165:            }
3166:
3167:            private static int getKeywordOrIdentifier(String s1, String s2,
3168:                    int keywordType) {
3169:                if (s1.equals(s2)) {
3170:                    return keywordType;
3171:                }
3172:                return IDENTIFIER;
3173:            }
3174:
3175:            private Column parseColumnForTable(String columnName)
3176:                    throws SQLException {
3177:                Column column;
3178:                if (readIf("IDENTITY") || readIf("SERIAL")) {
3179:                    column = new Column(columnName, Value.LONG);
3180:                    column.setOriginalSQL("IDENTITY");
3181:                    long start = 1, increment = 1;
3182:                    if (readIf("(")) {
3183:                        start = readLong();
3184:                        if (readIf(",")) {
3185:                            increment = readLong();
3186:                        }
3187:                        read(")");
3188:                    }
3189:                    column.setAutoIncrement(true, start, increment);
3190:                } else {
3191:                    column = parseColumn(columnName);
3192:                }
3193:                if (readIf("NOT")) {
3194:                    read("NULL");
3195:                    column.setNullable(false);
3196:                } else {
3197:                    readIf("NULL");
3198:                    column.setNullable(true);
3199:                }
3200:                if (readIf("AS")) {
3201:                    Expression expr = readExpression();
3202:                    column.setComputed(true, expr);
3203:                } else if (readIf("DEFAULT")) {
3204:                    Expression defaultExpression = readExpression();
3205:                    column.setDefaultExpression(session, defaultExpression);
3206:                } else if (readIf("GENERATED")) {
3207:                    read("BY");
3208:                    read("DEFAULT");
3209:                    read("AS");
3210:                    read("IDENTITY");
3211:                    long start = 1, increment = 1;
3212:                    if (readIf("(")) {
3213:                        read("START");
3214:                        readIf("WITH");
3215:                        start = readLong();
3216:                        readIf(",");
3217:                        if (readIf("INCREMENT")) {
3218:                            readIf("BY");
3219:                            increment = readLong();
3220:                        }
3221:                        read(")");
3222:                    }
3223:                    column.setAutoIncrement(true, start, increment);
3224:                }
3225:                if (readIf("NOT")) {
3226:                    read("NULL");
3227:                    column.setNullable(false);
3228:                } else {
3229:                    readIf("NULL");
3230:                }
3231:                if (readIf("AUTO_INCREMENT") || readIf("IDENTITY")) {
3232:                    long start = 1, increment = 1;
3233:                    if (readIf("(")) {
3234:                        start = readLong();
3235:                        if (readIf(",")) {
3236:                            increment = readLong();
3237:                        }
3238:                        read(")");
3239:                    }
3240:                    column.setAutoIncrement(true, start, increment);
3241:                    if (readIf("NOT")) {
3242:                        read("NULL");
3243:                    }
3244:                }
3245:                if (readIf("NULL_TO_DEFAULT")) {
3246:                    column.setConvertNullToDefault(true);
3247:                }
3248:                if (readIf("SEQUENCE")) {
3249:                    Sequence sequence = readSequence();
3250:                    column.setSequence(sequence);
3251:                }
3252:                if (readIf("SELECTIVITY")) {
3253:                    int value = getPositiveInt();
3254:                    column.setSelectivity(value);
3255:                }
3256:                column.setComment(readCommentIf());
3257:                return column;
3258:            }
3259:
3260:            private String readCommentIf() throws SQLException {
3261:                if (readIf("COMMENT")) {
3262:                    readIf("IS");
3263:                    return readString();
3264:                }
3265:                return null;
3266:            }
3267:
3268:            private Column parseColumn(String columnName) throws SQLException {
3269:                String original = currentToken;
3270:                boolean regular = false;
3271:                if (readIf("LONG")) {
3272:                    if (readIf("RAW")) {
3273:                        original += " RAW";
3274:                    }
3275:                } else if (readIf("DOUBLE")) {
3276:                    if (readIf("PRECISION")) {
3277:                        original += " PRECISION";
3278:                    }
3279:                } else if (readIf("CHARACTER")) {
3280:                    if (readIf("VARYING")) {
3281:                        original += " VARYING";
3282:                    }
3283:                } else {
3284:                    regular = true;
3285:                }
3286:                DataType dataType = DataType.getTypeByName(original);
3287:                long precision = -1;
3288:                int displaySize = -1;
3289:                int scale = -1;
3290:                Column templateColumn = null;
3291:                if (dataType == null) {
3292:                    UserDataType userDataType = database
3293:                            .findUserDataType(original);
3294:                    if (userDataType == null) {
3295:                        throw Message.getSQLException(
3296:                                ErrorCode.UNKNOWN_DATA_TYPE_1, currentToken);
3297:                    } else {
3298:                        templateColumn = userDataType.getColumn();
3299:                        dataType = DataType.getDataType(templateColumn
3300:                                .getType());
3301:                        original = templateColumn.getOriginalSQL();
3302:                        precision = templateColumn.getPrecision();
3303:                        displaySize = templateColumn.getDisplaySize();
3304:                        scale = templateColumn.getScale();
3305:                    }
3306:                }
3307:                if (database.getIgnoreCase() && dataType.type == Value.STRING
3308:                        && !"VARCHAR_CASESENSITIVE".equals(original)) {
3309:                    original = "VARCHAR_IGNORECASE";
3310:                    dataType = DataType.getTypeByName(original);
3311:                }
3312:                if (regular) {
3313:                    read();
3314:                }
3315:                precision = precision == -1 ? dataType.defaultPrecision
3316:                        : precision;
3317:                displaySize = displaySize == -1 ? dataType.defaultDisplaySize
3318:                        : displaySize;
3319:                scale = scale == -1 ? dataType.defaultScale : scale;
3320:                if (dataType.supportsPrecision || dataType.supportsScale) {
3321:                    if (readIf("(")) {
3322:                        precision = readLong();
3323:                        if (readIf("K")) {
3324:                            precision *= 1024;
3325:                        } else if (readIf("M")) {
3326:                            precision *= 1024 * 1024;
3327:                        } else if (readIf("G")) {
3328:                            precision *= 1024 * 1024 * 1024;
3329:                        }
3330:                        if (precision > Long.MAX_VALUE) {
3331:                            precision = Long.MAX_VALUE;
3332:                        }
3333:                        displaySize = MathUtils.convertLongToInt(precision);
3334:                        original += "(" + precision;
3335:                        // oracle syntax
3336:                        readIf("CHAR");
3337:                        if (dataType.supportsScale) {
3338:                            if (readIf(",")) {
3339:                                scale = getPositiveInt();
3340:                                original += ", " + scale;
3341:                            } else {
3342:                                scale = 0;
3343:                            }
3344:                        }
3345:                        original += ")";
3346:                        read(")");
3347:                    }
3348:                } else if (readIf("(")) {
3349:                    // support for MySQL: INT(11), MEDIUMINT(8) and so on. Just ignore
3350:                    // the precision.
3351:                    getPositiveInt();
3352:                    read(")");
3353:                }
3354:                if (readIf("FOR")) {
3355:                    read("BIT");
3356:                    read("DATA");
3357:                    if (dataType.type == Value.STRING) {
3358:                        dataType = DataType.getTypeByName("BINARY");
3359:                    }
3360:                }
3361:                int type = dataType.type;
3362:                Column column = new Column(columnName, type, precision, scale,
3363:                        displaySize);
3364:                if (templateColumn != null) {
3365:                    column.setNullable(templateColumn.getNullable());
3366:                    column.setDefaultExpression(session, templateColumn
3367:                            .getDefaultExpression());
3368:                    int selectivity = templateColumn.getSelectivity();
3369:                    if (selectivity != Constants.SELECTIVITY_DEFAULT) {
3370:                        column.setSelectivity(selectivity);
3371:                    }
3372:                    Expression checkConstraint = templateColumn
3373:                            .getCheckConstraint(session, columnName);
3374:                    if (checkConstraint != null) {
3375:                        column.addCheckConstraint(session, checkConstraint);
3376:                    }
3377:                }
3378:                column.setOriginalSQL(original);
3379:                return column;
3380:            }
3381:
3382:            private Prepared parseCreate() throws SQLException {
3383:                boolean force = readIf("FORCE");
3384:                if (readIf("LOCAL")) {
3385:                    read("TEMPORARY");
3386:                    read("TABLE");
3387:                    return parseCreateTable(true, false, false);
3388:                } else if (readIf("GLOBAL")) {
3389:                    read("TEMPORARY");
3390:                    read("TABLE");
3391:                    return parseCreateTable(true, true, false);
3392:                } else if (readIf("TEMP") || readIf("TEMPORARY")) {
3393:                    read("TABLE");
3394:                    return parseCreateTable(true, true, false);
3395:                } else if (readIf("MEMORY")) {
3396:                    read("TABLE");
3397:                    return parseCreateTable(false, false, false);
3398:                } else if (readIf("LINKED")) {
3399:                    return parseCreateLinkedTable(force);
3400:                } else if (readIf("CACHED")) {
3401:                    read("TABLE");
3402:                    return parseCreateTable(false, false, true);
3403:                } else if (readIf("TABLE")) {
3404:                    int defaultMode;
3405:                    Setting setting = database.findSetting(SetTypes
3406:                            .getTypeName(SetTypes.DEFAULT_TABLE_TYPE));
3407:                    defaultMode = setting == null ? Constants.DEFAULT_TABLE_TYPE
3408:                            : setting.getIntValue();
3409:                    return parseCreateTable(false, false,
3410:                            defaultMode == Table.TYPE_CACHED);
3411:                } else if (readIf("VIEW")) {
3412:                    return parseCreateView(force);
3413:                } else if (readIf("ALIAS")) {
3414:                    return parseCreateFunctionAlias(force);
3415:                } else if (readIf("SEQUENCE")) {
3416:                    return parseCreateSequence();
3417:                } else if (readIf("USER")) {
3418:                    return parseCreateUser();
3419:                } else if (readIf("TRIGGER")) {
3420:                    return parseCreateTrigger(force);
3421:                } else if (readIf("ROLE")) {
3422:                    return parseCreateRole();
3423:                } else if (readIf("SCHEMA")) {
3424:                    return parseCreateSchema();
3425:                } else if (readIf("CONSTANT")) {
3426:                    return parseCreateConstant();
3427:                } else if (readIf("DOMAIN")) {
3428:                    return parseCreateUserDataType();
3429:                } else if (readIf("TYPE")) {
3430:                    return parseCreateUserDataType();
3431:                } else if (readIf("DATATYPE")) {
3432:                    return parseCreateUserDataType();
3433:                } else if (readIf("AGGREGATE")) {
3434:                    return parseCreateAggregate(force);
3435:                } else {
3436:                    boolean hash = false, primaryKey = false, unique = false;
3437:                    String indexName = null;
3438:                    Schema oldSchema = null;
3439:                    boolean ifNotExists = false;
3440:                    if (readIf("PRIMARY")) {
3441:                        read("KEY");
3442:                        if (readIf("HASH")) {
3443:                            hash = true;
3444:                        }
3445:                        primaryKey = true;
3446:                    } else {
3447:                        if (readIf("UNIQUE")) {
3448:                            unique = true;
3449:                            if (readIf("HASH")) {
3450:                                hash = true;
3451:                            }
3452:                        }
3453:                        if (readIf("INDEX")) {
3454:                            if (!isToken("ON")) {
3455:                                ifNotExists = readIfNoExists();
3456:                                indexName = readIdentifierWithSchema(null);
3457:                                oldSchema = getSchema();
3458:                            }
3459:                        } else {
3460:                            throw getSyntaxError();
3461:                        }
3462:                    }
3463:                    read("ON");
3464:                    String tableName = readIdentifierWithSchema();
3465:                    checkSchema(oldSchema);
3466:                    CreateIndex command = new CreateIndex(session, getSchema());
3467:                    command.setIfNotExists(ifNotExists);
3468:                    command.setHash(hash);
3469:                    command.setPrimaryKey(primaryKey);
3470:                    command.setTableName(tableName);
3471:                    command.setUnique(unique);
3472:                    command.setIndexName(indexName);
3473:                    command.setComment(readCommentIf());
3474:                    read("(");
3475:                    command.setIndexColumns(parseIndexColumnList());
3476:                    return command;
3477:                }
3478:            }
3479:
3480:            private boolean addRoleOrRight(GrantRevoke command)
3481:                    throws SQLException {
3482:                if (readIf("SELECT")) {
3483:                    command.addRight(Right.SELECT);
3484:                    return false;
3485:                } else if (readIf("DELETE")) {
3486:                    command.addRight(Right.DELETE);
3487:                    return false;
3488:                } else if (readIf("INSERT")) {
3489:                    command.addRight(Right.INSERT);
3490:                    return false;
3491:                } else if (readIf("UPDATE")) {
3492:                    command.addRight(Right.UPDATE);
3493:                    return false;
3494:                } else if (readIf("ALL")) {
3495:                    command.addRight(Right.ALL);
3496:                    return false;
3497:                } else if (readIf("CONNECT")) {
3498:                    // ignore this right
3499:                    return false;
3500:                } else if (readIf("RESOURCE")) {
3501:                    // ignore this right
3502:                    return false;
3503:                } else {
3504:                    command.addRoleName(readUniqueIdentifier());
3505:                    return true;
3506:                }
3507:            }
3508:
3509:            private GrantRevoke parseGrantRevoke(int operationType)
3510:                    throws SQLException {
3511:                GrantRevoke command = new GrantRevoke(session);
3512:                command.setOperationType(operationType);
3513:                boolean isRoleBased = addRoleOrRight(command);
3514:                while (readIf(",")) {
3515:                    boolean next = addRoleOrRight(command);
3516:                    if (next != isRoleBased) {
3517:                        throw Message
3518:                                .getSQLException(ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED);
3519:                    }
3520:                }
3521:                if (!isRoleBased) {
3522:                    if (readIf("ON")) {
3523:                        do {
3524:                            Table table = readTableOrView();
3525:                            command.addTable(table);
3526:                        } while (readIf(","));
3527:                    }
3528:                }
3529:                if (operationType == GrantRevoke.GRANT) {
3530:                    read("TO");
3531:                } else {
3532:                    read("FROM");
3533:                }
3534:                command.setGranteeName(readUniqueIdentifier());
3535:                return command;
3536:            }
3537:
3538:            private Call parserCall() throws SQLException {
3539:                Call command = new Call(session);
3540:                currentPrepared = command;
3541:                command.setValue(readExpression());
3542:                return command;
3543:            }
3544:
3545:            private CreateRole parseCreateRole() throws SQLException {
3546:                CreateRole command = new CreateRole(session);
3547:                command.setIfNotExists(readIfNoExists());
3548:                command.setRoleName(readUniqueIdentifier());
3549:                return command;
3550:            }
3551:
3552:            private CreateSchema parseCreateSchema() throws SQLException {
3553:                CreateSchema command = new CreateSchema(session);
3554:                command.setIfNotExists(readIfNoExists());
3555:                command.setSchemaName(readUniqueIdentifier());
3556:                if (readIf("AUTHORIZATION")) {
3557:                    command.setAuthorization(readUniqueIdentifier());
3558:                } else {
3559:                    command.setAuthorization(session.getUser().getName());
3560:                }
3561:                return command;
3562:            }
3563:
3564:            private CreateSequence parseCreateSequence() throws SQLException {
3565:                boolean ifNotExists = readIfNoExists();
3566:                String sequenceName = readIdentifierWithSchema();
3567:                CreateSequence command = new CreateSequence(session,
3568:                        getSchema());
3569:                command.setIfNotExists(ifNotExists);
3570:                command.setSequenceName(sequenceName);
3571:                if (readIf("START")) {
3572:                    readIf("WITH");
3573:                    command.setStartWith(readExpression());
3574:                }
3575:                if (readIf("INCREMENT")) {
3576:                    readIf("BY");
3577:                    command.setIncrement(readExpression());
3578:                }
3579:                if (readIf("CACHE")) {
3580:                    command.setCacheSize(readExpression());
3581:                }
3582:                if (readIf("BELONGS_TO_TABLE")) {
3583:                    command.setBelongsToTable(true);
3584:                }
3585:                return command;
3586:            }
3587:
3588:            private boolean readIfNoExists() throws SQLException {
3589:                if (readIf("IF")) {
3590:                    read("NOT");
3591:                    read("EXISTS");
3592:                    return true;
3593:                }
3594:                return false;
3595:            }
3596:
3597:            private CreateConstant parseCreateConstant() throws SQLException {
3598:                boolean ifNotExists = readIfNoExists();
3599:                String constantName = readIdentifierWithSchema();
3600:                Schema schema = getSchema();
3601:                if (isKeyword(constantName)) {
3602:                    throw Message.getSQLException(
3603:                            ErrorCode.CONSTANT_ALREADY_EXISTS_1, constantName);
3604:                }
3605:                read("VALUE");
3606:                Expression expr = readExpression();
3607:                CreateConstant command = new CreateConstant(session, schema);
3608:                command.setConstantName(constantName);
3609:                command.setExpression(expr);
3610:                command.setIfNotExists(ifNotExists);
3611:                return command;
3612:            }
3613:
3614:            private CreateAggregate parseCreateAggregate(boolean force)
3615:                    throws SQLException {
3616:                boolean ifNotExists = readIfNoExists();
3617:                CreateAggregate command = new CreateAggregate(session);
3618:                command.setForce(force);
3619:                String name = readUniqueIdentifier();
3620:                if (isKeyword(name)
3621:                        || Function.getFunction(database, name) != null
3622:                        || Aggregate.getAggregateType(name) >= 0) {
3623:                    throw Message.getSQLException(
3624:                            ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1, name);
3625:                }
3626:                command.setName(name);
3627:                command.setIfNotExists(ifNotExists);
3628:                read("FOR");
3629:                command.setJavaClassMethod(readUniqueIdentifier());
3630:                return command;
3631:            }
3632:
3633:            private CreateUserDataType parseCreateUserDataType()
3634:                    throws SQLException {
3635:                boolean ifNotExists = readIfNoExists();
3636:                CreateUserDataType command = new CreateUserDataType(session);
3637:                command.setTypeName(readUniqueIdentifier());
3638:                read("AS");
3639:                Column col = parseColumnForTable("VALUE");
3640:                if (readIf("CHECK")) {
3641:                    Expression expr = readExpression();
3642:                    col.addCheckConstraint(session, expr);
3643:                }
3644:                col.rename(null);
3645:                command.setColumn(col);
3646:                command.setIfNotExists(ifNotExists);
3647:                return command;
3648:            }
3649:
3650:            private CreateTrigger parseCreateTrigger(boolean force)
3651:                    throws SQLException {
3652:                boolean ifNotExists = readIfNoExists();
3653:                String triggerName = readIdentifierWithSchema(null);
3654:                Schema schema = getSchema();
3655:                boolean isBefore;
3656:                if (readIf("BEFORE")) {
3657:                    isBefore = true;
3658:                } else {
3659:                    read("AFTER");
3660:                    isBefore = false;
3661:                }
3662:                int typeMask = 0;
3663:                do {
3664:                    if (readIf("INSERT")) {
3665:                        typeMask |= Trigger.INSERT;
3666:                    } else if (readIf("UPDATE")) {
3667:                        typeMask |= Trigger.UPDATE;
3668:                    } else if (readIf("DELETE")) {
3669:                        typeMask |= Trigger.DELETE;
3670:                    } else {
3671:                        throw getSyntaxError();
3672:                    }
3673:                } while (readIf(","));
3674:                read("ON");
3675:                String tableName = readIdentifierWithSchema();
3676:                checkSchema(schema);
3677:                CreateTrigger command = new CreateTrigger(session, getSchema());
3678:                command.setForce(force);
3679:                command.setTriggerName(triggerName);
3680:                command.setIfNotExists(ifNotExists);
3681:                command.setBefore(isBefore);
3682:                command.setTypeMask(typeMask);
3683:                command.setTableName(tableName);
3684:                if (readIf("FOR")) {
3685:                    read("EACH");
3686:                    read("ROW");
3687:                    command.setRowBased(true);
3688:                } else {
3689:                    command.setRowBased(false);
3690:                }
3691:                if (readIf("QUEUE")) {
3692:                    command.setQueueSize(getPositiveInt());
3693:                }
3694:                command.setNoWait(readIf("NOWAIT"));
3695:                read("CALL");
3696:                command.setTriggerClassName(readUniqueIdentifier());
3697:                return command;
3698:            }
3699:
3700:            private CreateUser parseCreateUser() throws SQLException {
3701:                CreateUser command = new CreateUser(session);
3702:                command.setIfNotExists(readIfNoExists());
3703:                command.setUserName(readUniqueIdentifier());
3704:                command.setComment(readCommentIf());
3705:                if (readIf("PASSWORD")) {
3706:                    command.setPassword(readString());
3707:                } else if (readIf("SALT")) {
3708:                    command.setSalt(readString());
3709:                    read("HASH");
3710:                    command.setHash(readString());
3711:                } else if (readIf("IDENTIFIED")) {
3712:                    read("BY");
3713:                    // uppercase if not quoted
3714:                    command.setPassword(readColumnIdentifier());
3715:                } else {
3716:                    throw getSyntaxError();
3717:                }
3718:                if (readIf("ADMIN")) {
3719:                    command.setAdmin(true);
3720:                }
3721:                return command;
3722:            }
3723:
3724:            private CreateFunctionAlias parseCreateFunctionAlias(boolean force)
3725:                    throws SQLException {
3726:                boolean ifNotExists = readIfNoExists();
3727:                CreateFunctionAlias command = new CreateFunctionAlias(session);
3728:                command.setForce(force);
3729:                String name = readUniqueIdentifier();
3730:                if (isKeyword(name)
3731:                        || Function.getFunction(database, name) != null
3732:                        || Aggregate.getAggregateType(name) >= 0) {
3733:                    throw Message.getSQLException(
3734:                            ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1, name);
3735:                }
3736:                command.setAliasName(name);
3737:                command.setIfNotExists(ifNotExists);
3738:                read("FOR");
3739:                command.setJavaClassMethod(readUniqueIdentifier());
3740:                return command;
3741:            }
3742:
3743:            private Query parserWith() throws SQLException {
3744:                String tempViewName = readIdentifierWithSchema();
3745:                Schema schema = getSchema();
3746:                TableData recursiveTable;
3747:                read("(");
3748:                String[] cols = parseColumnList();
3749:                ObjectArray columns = new ObjectArray();
3750:                for (int i = 0; i < cols.length; i++) {
3751:                    columns.add(new Column(cols[i], Value.STRING));
3752:                }
3753:                int id = database.allocateObjectId(true, true);
3754:                recursiveTable = schema.createTable(tempViewName, id, columns,
3755:                        false, false);
3756:                recursiveTable.setTemporary(true);
3757:                session.addLocalTempTable(recursiveTable);
3758:                String querySQL = StringCache.getNew(sqlCommand
3759:                        .substring(parseIndex));
3760:                read("AS");
3761:                Query withQuery = parseSelect();
3762:                withQuery.prepare();
3763:                session.removeLocalTempTable(recursiveTable);
3764:                id = database.allocateObjectId(true, true);
3765:                TableView view = new TableView(schema, id, tempViewName,
3766:                        querySQL, null, cols, session, true);
3767:                view.setTemporary(true);
3768:                // view.setOnCommitDrop(true);
3769:                session.addLocalTempTable(view);
3770:                Query query = parseSelect();
3771:                query.prepare();
3772:                query.setPrepareAlways(true);
3773:                // session.removeLocalTempTable(view);
3774:                return query;
3775:            }
3776:
3777:            private CreateView parseCreateView(boolean force)
3778:                    throws SQLException {
3779:                boolean ifNotExists = readIfNoExists();
3780:                String viewName = readIdentifierWithSchema();
3781:                CreateView command = new CreateView(session, getSchema());
3782:                this .prepared = command;
3783:                command.setViewName(viewName);
3784:                command.setIfNotExists(ifNotExists);
3785:                command.setComment(readCommentIf());
3786:                if (readIf("(")) {
3787:                    String[] cols = parseColumnList();
3788:                    command.setColumnNames(cols);
3789:                }
3790:                String select = StringCache.getNew(sqlCommand
3791:                        .substring(parseIndex));
3792:                read("AS");
3793:                try {
3794:                    Query query = parseSelect();
3795:                    query.prepare();
3796:                    command.setSelect(query);
3797:                } catch (SQLException e) {
3798:                    if (force) {
3799:                        command.setSelectSQL(select);
3800:                    } else {
3801:                        throw e;
3802:                    }
3803:                }
3804:                return command;
3805:            }
3806:
3807:            private TransactionCommand parseCheckpoint() throws SQLException {
3808:                TransactionCommand command;
3809:                if (readIf("SYNC")) {
3810:                    command = new TransactionCommand(session,
3811:                            TransactionCommand.CHECKPOINT_SYNC);
3812:                } else {
3813:                    command = new TransactionCommand(session,
3814:                            TransactionCommand.CHECKPOINT);
3815:                }
3816:                return command;
3817:            }
3818:
3819:            private Prepared parseAlter() throws SQLException {
3820:                if (readIf("TABLE")) {
3821:                    return parseAlterTable();
3822:                } else if (readIf("USER")) {
3823:                    return parseAlterUser();
3824:                } else if (readIf("INDEX")) {
3825:                    return parseAlterIndex();
3826:                } else if (readIf("SEQUENCE")) {
3827:                    return parseAlterSequence();
3828:                } else if (readIf("VIEW")) {
3829:                    return parseAlterView();
3830:                }
3831:                throw getSyntaxError();
3832:            }
3833:
3834:            private void checkSchema(Schema old) throws SQLException {
3835:                if (old != null && getSchema() != old) {
3836:                    throw Message
3837:                            .getSQLException(ErrorCode.SCHEMA_NAME_MUST_MATCH);
3838:                }
3839:            }
3840:
3841:            private AlterIndexRename parseAlterIndex() throws SQLException {
3842:                String indexName = readIdentifierWithSchema();
3843:                Schema old = getSchema();
3844:                AlterIndexRename command = new AlterIndexRename(session);
3845:                command.setOldIndex(getSchema().getIndex(indexName));
3846:                read("RENAME");
3847:                read("TO");
3848:                String newName = readIdentifierWithSchema(old.getName());
3849:                checkSchema(old);
3850:                command.setNewName(newName);
3851:                return command;
3852:            }
3853:
3854:            private AlterView parseAlterView() throws SQLException {
3855:                AlterView command = new AlterView(session);
3856:                String viewName = readIdentifierWithSchema();
3857:                Table tableView = getSchema()
3858:                        .findTableOrView(session, viewName);
3859:                if (!(tableView instanceof  TableView)) {
3860:                    throw Message.getSQLException(ErrorCode.VIEW_NOT_FOUND_1,
3861:                            viewName);
3862:                }
3863:                TableView view = (TableView) tableView;
3864:                command.setView(view);
3865:                read("RECOMPILE");
3866:                return command;
3867:            }
3868:
3869:            private AlterSequence parseAlterSequence() throws SQLException {
3870:                String sequenceName = readIdentifierWithSchema();
3871:                Sequence sequence = getSchema().getSequence(sequenceName);
3872:                AlterSequence command = new AlterSequence(session, sequence
3873:                        .getSchema());
3874:                command.setSequence(sequence);
3875:                if (readIf("RESTART")) {
3876:                    read("WITH");
3877:                    command.setStartWith(readExpression());
3878:                }
3879:                if (readIf("INCREMENT")) {
3880:                    read("BY");
3881:                    command.setIncrement(readExpression());
3882:                }
3883:                return command;
3884:            }
3885:
3886:            private AlterUser parseAlterUser() throws SQLException {
3887:                String userName = readUniqueIdentifier();
3888:                if (readIf("SET")) {
3889:                    AlterUser command = new AlterUser(session);
3890:                    command.setType(AlterUser.SET_PASSWORD);
3891:                    command.setUser(database.getUser(userName));
3892:                    if (readIf("PASSWORD")) {
3893:                        command.setPassword(readString());
3894:                    } else if (readIf("SALT")) {
3895:                        command.setSalt(readString());
3896:                        read("HASH");
3897:                        command.setHash(readString());
3898:                    } else {
3899:                        throw getSyntaxError();
3900:                    }
3901:                    return command;
3902:                } else if (readIf("RENAME")) {
3903:                    read("TO");
3904:                    AlterUser command = new AlterUser(session);
3905:                    command.setType(AlterUser.RENAME);
3906:                    command.setUser(database.getUser(userName));
3907:                    String newName = readUniqueIdentifier();
3908:                    command.setNewName(newName);
3909:                    return command;
3910:                } else if (readIf("ADMIN")) {
3911:                    AlterUser command = new AlterUser(session);
3912:                    command.setType(AlterUser.ADMIN);
3913:                    User user = database.getUser(userName);
3914:                    command.setUser(user);
3915:                    if (readIf("TRUE")) {
3916:                        command.setAdmin(true);
3917:                    } else if (readIf("FALSE")) {
3918:                        command.setAdmin(false);
3919:                    } else {
3920:                        throw getSyntaxError();
3921:                    }
3922:                    return command;
3923:                }
3924:                throw getSyntaxError();
3925:            }
3926:
3927:            private void readIfEqualOrTo() throws SQLException {
3928:                if (!readIf("=")) {
3929:                    readIf("TO");
3930:                }
3931:            }
3932:
3933:            private Prepared parseSet() throws SQLException {
3934:                if (readIf("@")) {
3935:                    Set command = new Set(session, SetTypes.VARIABLE);
3936:                    command.setString(readAliasIdentifier());
3937:                    readIfEqualOrTo();
3938:                    command.setExpression(readExpression());
3939:                    return command;
3940:                } else if (readIf("AUTOCOMMIT")) {
3941:                    readIfEqualOrTo();
3942:                    boolean value = readBooleanSetting();
3943:                    int setting = value ? TransactionCommand.AUTOCOMMIT_TRUE
3944:                            : TransactionCommand.AUTOCOMMIT_FALSE;
3945:                    return new TransactionCommand(session, setting);
3946:                } else if (readIf("MVCC")) {
3947:                    readIfEqualOrTo();
3948:                    boolean value = readBooleanSetting();
3949:                    Set command = new Set(session, SetTypes.MVCC);
3950:                    command.setInt(value ? 1 : 0);
3951:                    return command;
3952:                } else if (readIf("EXCLUSIVE")) {
3953:                    readIfEqualOrTo();
3954:                    boolean value = readBooleanSetting();
3955:                    Set command = new Set(session, SetTypes.EXCLUSIVE);
3956:                    command.setInt(value ? 1 : 0);
3957:                    return command;
3958:                } else if (readIf("IGNORECASE")) {
3959:                    readIfEqualOrTo();
3960:                    boolean value = readBooleanSetting();
3961:                    Set command = new Set(session, SetTypes.IGNORECASE);
3962:                    command.setInt(value ? 1 : 0);
3963:                    return command;
3964:                } else if (readIf("PASSWORD")) {
3965:                    readIfEqualOrTo();
3966:                    AlterUser command = new AlterUser(session);
3967:                    command.setType(AlterUser.SET_PASSWORD);
3968:                    command.setUser(session.getUser());
3969:                    command.setPassword(readString());
3970:                    return command;
3971:                } else if (readIf("SALT")) {
3972:                    readIfEqualOrTo();
3973:                    AlterUser command = new AlterUser(session);
3974:                    command.setType(AlterUser.SET_PASSWORD);
3975:                    command.setUser(session.getUser());
3976:                    command.setSalt(readString());
3977:                    read("HASH");
3978:                    command.setHash(readString());
3979:                    return command;
3980:                } else if (readIf("MODE")) {
3981:                    readIfEqualOrTo();
3982:                    Set command = new Set(session, SetTypes.MODE);
3983:                    command.setString(readAliasIdentifier());
3984:                    return command;
3985:                } else if (readIf("COMPRESS_LOB")) {
3986:                    readIfEqualOrTo();
3987:                    Set command = new Set(session, SetTypes.COMPRESS_LOB);
3988:                    if (currentTokenType == VALUE) {
3989:                        command.setString(readString());
3990:                    } else {
3991:                        command.setString(readUniqueIdentifier());
3992:                    }
3993:                    return command;
3994:                } else if (readIf("DATABASE")) {
3995:                    readIfEqualOrTo();
3996:                    read("COLLATION");
3997:                    return parseSetCollation();
3998:                } else if (readIf("COLLATION")) {
3999:                    readIfEqualOrTo();
4000:                    return parseSetCollation();
4001:                } else if (readIf("CLUSTER")) {
4002:                    readIfEqualOrTo();
4003:                    Set command = new Set(session, SetTypes.CLUSTER);
4004:                    command.setString(readString());
4005:                    return command;
4006:                } else if (readIf("DATABASE_EVENT_LISTENER")) {
4007:                    readIfEqualOrTo();
4008:                    Set command = new Set(session,
4009:                            SetTypes.DATABASE_EVENT_LISTENER);
4010:                    command.setString(readString());
4011:                    return command;
4012:                } else if (readIf("ALLOW_LITERALS")) {
4013:                    readIfEqualOrTo();
4014:                    Set command = new Set(session, SetTypes.ALLOW_LITERALS);
4015:                    if (readIf("NONE")) {
4016:                        command.setInt(Constants.ALLOW_LITERALS_NONE);
4017:                    } else if (readIf("ALL")) {
4018:                        command.setInt(Constants.ALLOW_LITERALS_ALL);
4019:                    } else if (readIf("NUMBERS")) {
4020:                        command.setInt(Constants.ALLOW_LITERALS_NUMBERS);
4021:                    } else {
4022:                        command.setInt(getPositiveInt());
4023:                    }
4024:                    return command;
4025:                } else if (readIf("DEFAULT_TABLE_TYPE")) {
4026:                    readIfEqualOrTo();
4027:                    Set command = new Set(session, SetTypes.DEFAULT_TABLE_TYPE);
4028:                    if (readIf("MEMORY")) {
4029:                        command.setInt(Table.TYPE_MEMORY);
4030:                    } else if (readIf("CACHED")) {
4031:                        command.setInt(Table.TYPE_CACHED);
4032:                    } else {
4033:                        command.setInt(getPositiveInt());
4034:                    }
4035:                    return command;
4036:                } else if (readIf("CREATE")) {
4037:                    readIfEqualOrTo();
4038:                    // Derby compatibility (CREATE=TRUE in the database URL)
4039:                    read();
4040:                    return new NoOperation(session);
4041:                } else if (readIf("HSQLDB.DEFAULT_TABLE_TYPE")) {
4042:                    readIfEqualOrTo();
4043:                    read();
4044:                    return new NoOperation(session);
4045:                } else if (readIf("CACHE_TYPE")) {
4046:                    readIfEqualOrTo();
4047:                    read();
4048:                    return new NoOperation(session);
4049:                } else if (readIf("FILE_LOCK")) {
4050:                    readIfEqualOrTo();
4051:                    read();
4052:                    return new NoOperation(session);
4053:                } else if (readIf("STORAGE")) {
4054:                    readIfEqualOrTo();
4055:                    read();
4056:                    return new NoOperation(session);
4057:                } else if (readIf("DB_CLOSE_ON_EXIT")) {
4058:                    readIfEqualOrTo();
4059:                    read();
4060:                    return new NoOperation(session);
4061:                } else if (readIf("ACCESS_MODE_LOG")) {
4062:                    readIfEqualOrTo();
4063:                    read();
4064:                    return new NoOperation(session);
4065:                } else if (readIf("ASSERT")) {
4066:                    readIfEqualOrTo();
4067:                    read();
4068:                    return new NoOperation(session);
4069:                } else if (readIf("ACCESS_MODE_DATA")) {
4070:                    readIfEqualOrTo();
4071:                    read();
4072:                    return new NoOperation(session);
4073:                } else if (readIf("DATABASE_EVENT_LISTENER_OBJECT")) {
4074:                    readIfEqualOrTo();
4075:                    read();
4076:                    return new NoOperation(session);
4077:                } else if (readIf("RECOVER")) {
4078:                    readIfEqualOrTo();
4079:                    read();
4080:                    return new NoOperation(session);
4081:                } else if (readIf("SCHEMA")) {
4082:                    readIfEqualOrTo();
4083:                    Set command = new Set(session, SetTypes.SCHEMA);
4084:                    command.setString(readAliasIdentifier());
4085:                    return command;
4086:                } else if (readIf("DATESTYLE")) {
4087:                    // PostgreSQL compatibility
4088:                    readIfEqualOrTo();
4089:                    read("ISO");
4090:                    return new NoOperation(session);
4091:                } else if (readIf("SEARCH_PATH")
4092:                        || readIf(SetTypes
4093:                                .getTypeName(SetTypes.SCHEMA_SEARCH_PATH))) {
4094:                    readIfEqualOrTo();
4095:                    Set command = new Set(session, SetTypes.SCHEMA_SEARCH_PATH);
4096:                    ObjectArray list = new ObjectArray();
4097:                    list.add(readAliasIdentifier());
4098:                    while (readIf(",")) {
4099:                        list.add(readAliasIdentifier());
4100:                    }
4101:                    String[] schemaNames = new String[list.size()];
4102:                    list.toArray(schemaNames);
4103:                    command.setStringArray(schemaNames);
4104:                    return command;
4105:                } else {
4106:                    if (isToken("LOGSIZE")) {
4107:                        // HSQLDB compatibility
4108:                        currentToken = SetTypes
4109:                                .getTypeName(SetTypes.MAX_LOG_SIZE);
4110:                    }
4111:                    int type = SetTypes.getType(currentToken);
4112:                    if (type >= 0) {
4113:                        read();
4114:                        readIfEqualOrTo();
4115:                        Set command = new Set(session, type);
4116:                        command.setExpression(readExpression());
4117:                        return command;
4118:                    } else {
4119:                        throw getSyntaxError();
4120:                    }
4121:                }
4122:            }
4123:
4124:            private Set parseSetCollation() throws SQLException {
4125:                Set command = new Set(session, SetTypes.COLLATION);
4126:                String name = readAliasIdentifier();
4127:                command.setString(name);
4128:                if (name.equals(CompareMode.OFF)) {
4129:                    return command;
4130:                }
4131:                Collator coll = CompareMode.getCollator(name);
4132:                if (coll == null) {
4133:                    throw getSyntaxError();
4134:                }
4135:                if (readIf("STRENGTH")) {
4136:                    if (readIf("PRIMARY")) {
4137:                        command.setInt(Collator.PRIMARY);
4138:                    } else if (readIf("SECONDARY")) {
4139:                        command.setInt(Collator.SECONDARY);
4140:                    } else if (readIf("TERTIARY")) {
4141:                        command.setInt(Collator.TERTIARY);
4142:                    } else if (readIf("IDENTICAL")) {
4143:                        command.setInt(Collator.IDENTICAL);
4144:                    }
4145:                } else {
4146:                    command.setInt(coll.getStrength());
4147:                }
4148:                return command;
4149:            }
4150:
4151:            private RunScriptCommand parseRunScript() throws SQLException {
4152:                RunScriptCommand command = new RunScriptCommand(session);
4153:                read("FROM");
4154:                command.setFileName(readString());
4155:                if (readIf("COMPRESSION")) {
4156:                    command.setCompressionAlgorithm(readUniqueIdentifier());
4157:                }
4158:                if (readIf("CIPHER")) {
4159:                    command.setCipher(readUniqueIdentifier());
4160:                    if (readIf("PASSWORD")) {
4161:                        command.setPassword(readString().toCharArray());
4162:                    }
4163:                }
4164:                if (readIf("CHARSET")) {
4165:                    command.setCharset(readString());
4166:                }
4167:                return command;
4168:            }
4169:
4170:            private ScriptCommand parseScript() throws SQLException {
4171:                ScriptCommand command = new ScriptCommand(session);
4172:                boolean data = true, passwords = true, settings = true, dropTables = false, simple = false;
4173:                if (readIf("SIMPLE")) {
4174:                    simple = true;
4175:                }
4176:                if (readIf("NODATA")) {
4177:                    data = false;
4178:                }
4179:                if (readIf("NOPASSWORDS")) {
4180:                    passwords = false;
4181:                }
4182:                if (readIf("NOSETTINGS")) {
4183:                    settings = false;
4184:                }
4185:                if (readIf("DROP")) {
4186:                    dropTables = true;
4187:                }
4188:                if (readIf("BLOCKSIZE")) {
4189:                    long blockSize = readLong();
4190:                    command.setLobBlockSize(blockSize);
4191:                }
4192:                command.setData(data);
4193:                command.setPasswords(passwords);
4194:                command.setSettings(settings);
4195:                command.setDrop(dropTables);
4196:                command.setSimple(simple);
4197:                if (readIf("TO")) {
4198:                    command.setFileName(readString());
4199:                    if (readIf("COMPRESSION")) {
4200:                        command.setCompressionAlgorithm(readUniqueIdentifier());
4201:                    }
4202:                    if (readIf("CIPHER")) {
4203:                        command.setCipher(readUniqueIdentifier());
4204:                        if (readIf("PASSWORD")) {
4205:                            command.setPassword(readString().toCharArray());
4206:                        }
4207:                    }
4208:                }
4209:                return command;
4210:            }
4211:
4212:            private Table readTableOrView() throws SQLException {
4213:                return readTableOrView(readIdentifierWithSchema(null));
4214:            }
4215:
4216:            private Table readTableOrView(String tableName) throws SQLException {
4217:                // same algorithm than readSequence
4218:                if (schemaName != null) {
4219:                    return getSchema().getTableOrView(session, tableName);
4220:                }
4221:                Table table = database
4222:                        .getSchema(session.getCurrentSchemaName())
4223:                        .findTableOrView(session, tableName);
4224:                if (table != null) {
4225:                    return table;
4226:                }
4227:                String[] schemaNames = session.getSchemaSearchPath();
4228:                for (int i = 0; schemaNames != null && i < schemaNames.length; i++) {
4229:                    Schema s = database.getSchema(schemaNames[i]);
4230:                    table = s.findTableOrView(session, tableName);
4231:                    if (table != null) {
4232:                        return table;
4233:                    }
4234:                }
4235:                throw Message.getSQLException(
4236:                        ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableName);
4237:            }
4238:
4239:            private Sequence readSequence() throws SQLException {
4240:                // same algorithm than readTableOrView
4241:                String sequenceName = readIdentifierWithSchema(null);
4242:                if (schemaName != null) {
4243:                    return getSchema().getSequence(sequenceName);
4244:                }
4245:                Sequence sequence = database.getSchema(
4246:                        session.getCurrentSchemaName()).findSequence(
4247:                        sequenceName);
4248:                if (sequence != null) {
4249:                    return sequence;
4250:                }
4251:                String[] schemaNames = session.getSchemaSearchPath();
4252:                for (int i = 0; schemaNames != null && i < schemaNames.length; i++) {
4253:                    Schema s = database.getSchema(schemaNames[i]);
4254:                    sequence = s.findSequence(sequenceName);
4255:                    if (sequence != null) {
4256:                        return sequence;
4257:                    }
4258:                }
4259:                throw Message.getSQLException(ErrorCode.SEQUENCE_NOT_FOUND_1,
4260:                        sequenceName);
4261:            }
4262:
4263:            private Prepared parseAlterTable() throws SQLException {
4264:                Table table = readTableOrView();
4265:                if (readIf("ADD")) {
4266:                    Prepared command = parseAlterTableAddConstraintIf(table
4267:                            .getName(), table.getSchema());
4268:                    if (command != null) {
4269:                        return command;
4270:                    }
4271:                    return parseAlterTableAddColumn(table);
4272:                } else if (readIf("SET")) {
4273:                    read("REFERENTIAL_INTEGRITY");
4274:                    int type;
4275:                    if (readIf("TRUE")) {
4276:                        type = AlterTableSet.REFERENTIAL_INTEGRITY_TRUE;
4277:                    } else {
4278:                        read("FALSE");
4279:                        type = AlterTableSet.REFERENTIAL_INTEGRITY_FALSE;
4280:                    }
4281:                    AlterTableSet command = new AlterTableSet(session, table
4282:                            .getSchema(), type);
4283:                    command.setTableName(table.getName());
4284:                    if (readIf("CHECK")) {
4285:                        command.setCheckExisting(true);
4286:                    } else if (readIf("NOCHECK")) {
4287:                        command.setCheckExisting(false);
4288:                    }
4289:                    return command;
4290:                } else if (readIf("RENAME")) {
4291:                    read("TO");
4292:                    String newName = readIdentifierWithSchema(table.getSchema()
4293:                            .getName());
4294:                    checkSchema(table.getSchema());
4295:                    AlterTableRename command = new AlterTableRename(session,
4296:                            getSchema());
4297:                    command.setOldTable(table);
4298:                    command.setNewTableName(newName);
4299:                    return command;
4300:                } else if (readIf("DROP")) {
4301:                    if (readIf("CONSTRAINT")) {
4302:                        String constraintName = readIdentifierWithSchema(table
4303:                                .getSchema().getName());
4304:                        checkSchema(table.getSchema());
4305:                        AlterTableDropConstraint command = new AlterTableDropConstraint(
4306:                                session, getSchema());
4307:                        command.setConstraintName(constraintName);
4308:                        return command;
4309:                    } else if (readIf("PRIMARY")) {
4310:                        read("KEY");
4311:                        Index idx = table.getPrimaryKey();
4312:                        DropIndex command = new DropIndex(session, table
4313:                                .getSchema());
4314:                        command.setIndexName(idx.getName());
4315:                        return command;
4316:                    } else {
4317:                        readIf("COLUMN");
4318:                        AlterTableAlterColumn command = new AlterTableAlterColumn(
4319:                                session, table.getSchema());
4320:                        command.setType(AlterTableAlterColumn.DROP);
4321:                        String columnName = readColumnIdentifier();
4322:                        command.setTable(table);
4323:                        command.setOldColumn(table.getColumn(columnName));
4324:                        return command;
4325:                    }
4326:                } else if (readIf("ALTER")) {
4327:                    readIf("COLUMN");
4328:                    String columnName = readColumnIdentifier();
4329:                    Column column = table.getColumn(columnName);
4330:                    if (readIf("RENAME")) {
4331:                        read("TO");
4332:                        AlterTableRenameColumn command = new AlterTableRenameColumn(
4333:                                session);
4334:                        command.setTable(table);
4335:                        command.setColumn(column);
4336:                        String newName = readColumnIdentifier();
4337:                        command.setNewColumnName(newName);
4338:                        return command;
4339:                    } else if (readIf("SET")) {
4340:                        if (readIf("DATA")) {
4341:                            // Derby compatibility
4342:                            read("TYPE");
4343:                            Column newColumn = parseColumnForTable(columnName);
4344:                            AlterTableAlterColumn command = new AlterTableAlterColumn(
4345:                                    session, table.getSchema());
4346:                            command.setTable(table);
4347:                            command.setType(AlterTableAlterColumn.CHANGE_TYPE);
4348:                            command.setOldColumn(column);
4349:                            command.setNewColumn(newColumn);
4350:                            return command;
4351:                        }
4352:                        AlterTableAlterColumn command = new AlterTableAlterColumn(
4353:                                session, table.getSchema());
4354:                        command.setTable(table);
4355:                        command.setOldColumn(column);
4356:                        if (readIf("NULL")) {
4357:                            command.setType(AlterTableAlterColumn.NULL);
4358:                            return command;
4359:                        } else if (readIf("NOT")) {
4360:                            read("NULL");
4361:                            command.setType(AlterTableAlterColumn.NOT_NULL);
4362:                            return command;
4363:                        } else if (readIf("DEFAULT")) {
4364:                            Expression defaultExpression = readExpression();
4365:                            command.setType(AlterTableAlterColumn.DEFAULT);
4366:                            command.setDefaultExpression(defaultExpression);
4367:                            return command;
4368:                        }
4369:                    } else if (readIf("RESTART")) {
4370:                        readIf("WITH");
4371:                        Expression start = readExpression();
4372:                        AlterSequence command = new AlterSequence(session,
4373:                                table.getSchema());
4374:                        command.setColumn(column);
4375:                        command.setStartWith(start);
4376:                        return command;
4377:                    } else if (readIf("SELECTIVITY")) {
4378:                        AlterTableAlterColumn command = new AlterTableAlterColumn(
4379:                                session, table.getSchema());
4380:                        command.setTable(table);
4381:                        command.setType(AlterTableAlterColumn.SELECTIVITY);
4382:                        command.setOldColumn(column);
4383:                        command.setSelectivity(readExpression());
4384:                        return command;
4385:                    } else {
4386:                        Column newColumn = parseColumnForTable(columnName);
4387:                        AlterTableAlterColumn command = new AlterTableAlterColumn(
4388:                                session, table.getSchema());
4389:                        command.setTable(table);
4390:                        command.setType(AlterTableAlterColumn.CHANGE_TYPE);
4391:                        command.setOldColumn(column);
4392:                        command.setNewColumn(newColumn);
4393:                        return command;
4394:                    }
4395:                }
4396:                throw getSyntaxError();
4397:            }
4398:
4399:            private AlterTableAlterColumn parseAlterTableAddColumn(Table table)
4400:                    throws SQLException {
4401:                readIf("COLUMN");
4402:                Schema schema = table.getSchema();
4403:                AlterTableAlterColumn command = new AlterTableAlterColumn(
4404:                        session, schema);
4405:                command.setType(AlterTableAlterColumn.ADD);
4406:                command.setTable(table);
4407:                String columnName = readColumnIdentifier();
4408:                Column column = parseColumnForTable(columnName);
4409:                command.setNewColumn(column);
4410:                if (readIf("BEFORE")) {
4411:                    command.setAddBefore(readColumnIdentifier());
4412:                }
4413:                return command;
4414:            }
4415:
4416:            private int parseAction() throws SQLException {
4417:                if (readIf("CASCADE")) {
4418:                    return ConstraintReferential.CASCADE;
4419:                } else if (readIf("RESTRICT")) {
4420:                    return ConstraintReferential.RESTRICT;
4421:                } else if (readIf("NO")) {
4422:                    read("ACTION");
4423:                    return ConstraintReferential.RESTRICT;
4424:                } else {
4425:                    read("SET");
4426:                    if (readIf("NULL")) {
4427:                        return ConstraintReferential.SET_NULL;
4428:                    } else {
4429:                        read("DEFAULT");
4430:                        return ConstraintReferential.SET_DEFAULT;
4431:                    }
4432:                }
4433:            }
4434:
4435:            private Prepared parseAlterTableAddConstraintIf(String tableName,
4436:                    Schema schema) throws SQLException {
4437:                String constraintName = null, comment = null;
4438:                if (readIf("CONSTRAINT")) {
4439:                    constraintName = readIdentifierWithSchema(schema.getName());
4440:                    checkSchema(schema);
4441:                    comment = readCommentIf();
4442:                }
4443:                if (readIf("PRIMARY")) {
4444:                    read("KEY");
4445:                    AlterTableAddConstraint command = new AlterTableAddConstraint(
4446:                            session, schema);
4447:                    command.setType(AlterTableAddConstraint.PRIMARY_KEY);
4448:                    command.setComment(comment);
4449:                    command.setConstraintName(constraintName);
4450:                    command.setTableName(tableName);
4451:                    if (readIf("HASH")) {
4452:                        command.setPrimaryKeyHash(true);
4453:                    }
4454:                    read("(");
4455:                    command.setIndexColumns(parseIndexColumnList());
4456:                    if (readIf("INDEX")) {
4457:                        String indexName = readIdentifierWithSchema();
4458:                        command.setIndex(getSchema().findIndex(indexName));
4459:                    }
4460:                    return command;
4461:                } else if (database.getMode().indexDefinitionInCreateTable
4462:                        && (readIf("INDEX") || readIf("KEY"))) {
4463:                    // MySQL
4464:                    CreateIndex command = new CreateIndex(session, schema);
4465:                    command.setComment(comment);
4466:                    command.setTableName(tableName);
4467:                    if (!readIf("(")) {
4468:                        command.setIndexName(readUniqueIdentifier());
4469:                        read("(");
4470:                    }
4471:                    command.setIndexColumns(parseIndexColumnList());
4472:                    return command;
4473:                }
4474:                AlterTableAddConstraint command;
4475:                if (readIf("CHECK")) {
4476:                    command = new AlterTableAddConstraint(session, schema);
4477:                    command.setType(AlterTableAddConstraint.CHECK);
4478:                    command.setCheckExpression(readExpression());
4479:                } else if (readIf("UNIQUE")) {
4480:                    readIf("INDEX");
4481:                    command = new AlterTableAddConstraint(session, schema);
4482:                    command.setType(AlterTableAddConstraint.UNIQUE);
4483:                    if (!readIf("(")) {
4484:                        constraintName = readUniqueIdentifier();
4485:                        read("(");
4486:                    }
4487:                    command.setIndexColumns(parseIndexColumnList());
4488:                    if (readIf("INDEX")) {
4489:                        String indexName = readIdentifierWithSchema();
4490:                        command.setIndex(getSchema().findIndex(indexName));
4491:                    }
4492:                } else if (readIf("FOREIGN")) {
4493:                    command = new AlterTableAddConstraint(session, schema);
4494:                    command.setType(AlterTableAddConstraint.REFERENTIAL);
4495:                    read("KEY");
4496:                    read("(");
4497:                    command.setIndexColumns(parseIndexColumnList());
4498:                    if (readIf("INDEX")) {
4499:                        String indexName = readIdentifierWithSchema();
4500:                        command.setIndex(schema.findIndex(indexName));
4501:                    }
4502:                    read("REFERENCES");
4503:                    parseReferences(command, schema, tableName);
4504:                } else {
4505:                    if (constraintName != null) {
4506:                        throw getSyntaxError();
4507:                    }
4508:                    return null;
4509:                }
4510:                if (readIf("NOCHECK")) {
4511:                    command.setCheckExisting(false);
4512:                } else {
4513:                    readIf("CHECK");
4514:                    command.setCheckExisting(true);
4515:                }
4516:                command.setTableName(tableName);
4517:                command.setConstraintName(constraintName);
4518:                command.setComment(comment);
4519:                return command;
4520:            }
4521:
4522:            private void parseReferences(AlterTableAddConstraint command,
4523:                    Schema schema, String tableName) throws SQLException {
4524:                if (readIf("(")) {
4525:                    command.setRefTableName(schema, tableName);
4526:                    command.setRefIndexColumns(parseIndexColumnList());
4527:                } else {
4528:                    String refTableName = readIdentifierWithSchema(schema
4529:                            .getName());
4530:                    command.setRefTableName(getSchema(), refTableName);
4531:                    if (readIf("(")) {
4532:                        command.setRefIndexColumns(parseIndexColumnList());
4533:                    }
4534:                }
4535:                if (readIf("INDEX")) {
4536:                    String indexName = readIdentifierWithSchema();
4537:                    command.setRefIndex(getSchema().findIndex(indexName));
4538:                }
4539:                while (readIf("ON")) {
4540:                    if (readIf("DELETE")) {
4541:                        command.setDeleteAction(parseAction());
4542:                    } else {
4543:                        read("UPDATE");
4544:                        command.setUpdateAction(parseAction());
4545:                    }
4546:                }
4547:                if (readIf("NOT")) {
4548:                    read("DEFERRABLE");
4549:                } else {
4550:                    readIf("DEFERRABLE");
4551:                }
4552:            }
4553:
4554:            private CreateLinkedTable parseCreateLinkedTable(boolean force)
4555:                    throws SQLException {
4556:                read("TABLE");
4557:                boolean ifNotExists = readIfNoExists();
4558:                String tableName = readIdentifierWithSchema();
4559:                CreateLinkedTable command = new CreateLinkedTable(session,
4560:                        getSchema());
4561:                command.setForce(force);
4562:                command.setIfNotExists(ifNotExists);
4563:                command.setTableName(tableName);
4564:                command.setComment(readCommentIf());
4565:                read("(");
4566:                command.setDriver(readString());
4567:                read(",");
4568:                command.setUrl(readString());
4569:                read(",");
4570:                command.setUser(readString());
4571:                read(",");
4572:                command.setPassword(readString());
4573:                read(",");
4574:                command.setOriginalTable(readString());
4575:                read(")");
4576:                if (readIf("EMIT")) {
4577:                    read("UPDATES");
4578:                    command.setEmitUpdates(true);
4579:                }
4580:                return command;
4581:            }
4582:
4583:            private CreateTable parseCreateTable(boolean temp,
4584:                    boolean globalTemp, boolean persistent) throws SQLException {
4585:                boolean ifNotExists = readIfNoExists();
4586:                String tableName = readIdentifierWithSchema();
4587:                if (temp && globalTemp && "SESSION".equals(schemaName)) {
4588:                    // support weird syntax: declare global temporary table session.xy
4589:                    // (...) not logged
4590:                    schemaName = session.getCurrentSchemaName();
4591:                    globalTemp = false;
4592:                }
4593:                Schema schema = getSchema();
4594:                CreateTable command = new CreateTable(session, schema);
4595:                command.setPersistent(persistent);
4596:                command.setTemporary(temp);
4597:                command.setGlobalTemporary(globalTemp);
4598:                command.setIfNotExists(ifNotExists);
4599:                command.setTableName(tableName);
4600:                command.setComment(readCommentIf());
4601:                if (readIf("AS")) {
4602:                    command.setQuery(parseSelect());
4603:                } else {
4604:                    read("(");
4605:                    if (!readIf(")")) {
4606:                        do {
4607:                            Prepared c = parseAlterTableAddConstraintIf(
4608:                                    tableName, schema);
4609:                            if (c != null) {
4610:                                command.addConstraintCommand(c);
4611:                            } else {
4612:                                String columnName = readColumnIdentifier();
4613:                                Column column = parseColumnForTable(columnName);
4614:                                if (column.getAutoIncrement()) {
4615:                                    IndexColumn[] cols = new IndexColumn[] { new IndexColumn() };
4616:                                    cols[0].columnName = column.getName();
4617:                                    AlterTableAddConstraint pk = new AlterTableAddConstraint(
4618:                                            session, schema);
4619:                                    pk
4620:                                            .setType(AlterTableAddConstraint.PRIMARY_KEY);
4621:                                    pk.setTableName(tableName);
4622:                                    pk.setIndexColumns(cols);
4623:                                    command.addConstraintCommand(pk);
4624:                                }
4625:                                command.addColumn(column);
4626:                                String constraintName = null;
4627:                                if (readIf("CONSTRAINT")) {
4628:                                    constraintName = readColumnIdentifier();
4629:                                }
4630:                                if (readIf("PRIMARY")) {
4631:                                    read("KEY");
4632:                                    boolean hash = readIf("HASH");
4633:                                    IndexColumn[] cols = new IndexColumn[] { new IndexColumn() };
4634:                                    cols[0].columnName = column.getName();
4635:                                    AlterTableAddConstraint pk = new AlterTableAddConstraint(
4636:                                            session, schema);
4637:                                    pk.setPrimaryKeyHash(hash);
4638:                                    pk
4639:                                            .setType(AlterTableAddConstraint.PRIMARY_KEY);
4640:                                    pk.setTableName(tableName);
4641:                                    pk.setIndexColumns(cols);
4642:                                    command.addConstraintCommand(pk);
4643:                                } else if (readIf("UNIQUE")) {
4644:                                    AlterTableAddConstraint unique = new AlterTableAddConstraint(
4645:                                            session, schema);
4646:                                    unique.setConstraintName(constraintName);
4647:                                    unique
4648:                                            .setType(AlterTableAddConstraint.UNIQUE);
4649:                                    IndexColumn[] cols = new IndexColumn[] { new IndexColumn() };
4650:                                    cols[0].columnName = columnName;
4651:                                    unique.setIndexColumns(cols);
4652:                                    unique.setTableName(tableName);
4653:                                    command.addConstraintCommand(unique);
4654:                                }
4655:                                if (readIf("CHECK")) {
4656:                                    Expression expr = readExpression();
4657:                                    column.addCheckConstraint(session, expr);
4658:                                }
4659:                                if (readIf("REFERENCES")) {
4660:                                    AlterTableAddConstraint ref = new AlterTableAddConstraint(
4661:                                            session, schema);
4662:                                    ref.setConstraintName(constraintName);
4663:                                    ref
4664:                                            .setType(AlterTableAddConstraint.REFERENTIAL);
4665:                                    IndexColumn[] cols = new IndexColumn[] { new IndexColumn() };
4666:                                    cols[0].columnName = columnName;
4667:                                    ref.setIndexColumns(cols);
4668:                                    ref.setTableName(tableName);
4669:                                    parseReferences(ref, schema, tableName);
4670:                                    command.addConstraintCommand(ref);
4671:                                }
4672:                            }
4673:                        } while (readIf(","));
4674:                        read(")");
4675:                    }
4676:                    if (readIf("AS")) {
4677:                        command.setQuery(parseSelect());
4678:                    }
4679:                }
4680:                if (temp) {
4681:                    if (readIf("ON")) {
4682:                        read("COMMIT");
4683:                        if (readIf("DROP")) {
4684:                            command.setOnCommitDrop();
4685:                        } else if (readIf("DELETE")) {
4686:                            read("ROWS");
4687:                            command.setOnCommitTruncate();
4688:                        }
4689:                    } else if (readIf("NOT")) {
4690:                        read("LOGGED");
4691:                    }
4692:                }
4693:                if (readIf("CLUSTERED")) {
4694:                    command.setClustered(true);
4695:                }
4696:                return command;
4697:            }
4698:
4699:            private int getCompareType(int tokenType) {
4700:                switch (tokenType) {
4701:                case EQUAL:
4702:                    return Comparison.EQUAL;
4703:                case BIGGER_EQUAL:
4704:                    return Comparison.BIGGER_EQUAL;
4705:                case BIGGER:
4706:                    return Comparison.BIGGER;
4707:                case SMALLER:
4708:                    return Comparison.SMALLER;
4709:                case SMALLER_EQUAL:
4710:                    return Comparison.SMALLER_EQUAL;
4711:                case NOT_EQUAL:
4712:                    return Comparison.NOT_EQUAL;
4713:                default:
4714:                    return -1;
4715:                }
4716:            }
4717:
4718:            /**
4719:             * Add double quotes around an identifier if required.
4720:             * 
4721:             * @param s the identifier
4722:             * @return the quoted identifier
4723:             */
4724:            public static String quoteIdentifier(String s) {
4725:                if (s == null || s.length() == 0) {
4726:                    return "\"\"";
4727:                }
4728:                char c = s.charAt(0);
4729:                // lowercase a-z is quoted as well
4730:                if ((!Character.isLetter(c) && c != '_')
4731:                        || Character.isLowerCase(c)) {
4732:                    return StringUtils.quoteIdentifier(s);
4733:                }
4734:                for (int i = 0; i < s.length(); i++) {
4735:                    c = s.charAt(i);
4736:                    if ((!Character.isLetterOrDigit(c) && c != '_')
4737:                            || Character.isLowerCase(c)) {
4738:                        return StringUtils.quoteIdentifier(s);
4739:                    }
4740:                }
4741:                if (Parser.isKeyword(s)) {
4742:                    return StringUtils.quoteIdentifier(s);
4743:                }
4744:                return s;
4745:            }
4746:
4747:            public void setRightsChecked(boolean rightsChecked) {
4748:                this .rightsChecked = rightsChecked;
4749:            }
4750:
4751:            /**
4752:             * Parse a SQL code snippet that represents an expression.
4753:             * 
4754:             * @param sql the code snippet
4755:             * @return the expression object
4756:             * @throws SQLException if the code snipped could not be parsed
4757:             */
4758:            public Expression parseExpression(String sql) throws SQLException {
4759:                parameters = new ObjectArray();
4760:                initialize(sql);
4761:                read();
4762:                return readExpression();
4763:            }
4764:
4765:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.