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: }
|