/*
* Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*
* Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888
* Support for the operator "&&" as an alias for SPATIAL_INTERSECTS
*/
package com.redspr.redquerybuilder.core.client.command;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import com.redspr.redquerybuilder.core.client.command.dml.Query;
import com.redspr.redquerybuilder.core.client.command.dml.Select;
import com.redspr.redquerybuilder.core.client.command.dml.SelectUnion;
import com.redspr.redquerybuilder.core.client.constant.ErrorCode;
import com.redspr.redquerybuilder.core.client.engine.Session;
import com.redspr.redquerybuilder.core.client.expression.Comparison;
import com.redspr.redquerybuilder.core.client.expression.ConditionAndOr;
import com.redspr.redquerybuilder.core.client.expression.Expression;
import com.redspr.redquerybuilder.core.client.expression.ExpressionColumn;
import com.redspr.redquerybuilder.core.client.expression.Null;
import com.redspr.redquerybuilder.core.client.expression.Parameter;
import com.redspr.redquerybuilder.core.client.table.TableFilter;
import com.redspr.redquerybuilder.core.client.util.ObjectArray;
import com.redspr.redquerybuilder.core.client.util.StatementBuilder;
import com.redspr.redquerybuilder.core.client.value.Value;
import com.redspr.redquerybuilder.core.shared.meta.Column;
import com.redspr.redquerybuilder.core.shared.meta.Database;
import com.redspr.redquerybuilder.core.shared.meta.Operator;
import com.redspr.redquerybuilder.core.shared.meta.Schema;
import com.redspr.redquerybuilder.core.shared.meta.Table;
/**
* The parser is used to convert a SQL statement string to an command object.
*/
public class Parser {
// used during the tokenizer phase
private static final int CHAR_END = -1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
private static final int CHAR_NAME = 4, CHAR_SPECIAL_1 = 5, CHAR_SPECIAL_2 = 6;
private static final int CHAR_STRING = 7, CHAR_DECIMAL = 8, CHAR_DOLLAR_QUOTED_STRING = 9;
// this are token types
private static final int KEYWORD = 1, IDENTIFIER = 2, PARAMETER = 3, END = 4, VALUE = 5;
private static final int EQUAL = 6, BIGGER_EQUAL = 7, BIGGER = 8;
private static final int SMALLER = 9, SMALLER_EQUAL = 10, NOT_EQUAL = 11, AT = 12;
private static final int MINUS = 17, PLUS = 18;
private static final int STRING_CONCAT = 22;
private static final int OPEN = 31, CLOSE = 32, NULL = 34, TRUE = 40, FALSE = 41;
private static final int CURRENT_TIMESTAMP = 42, CURRENT_DATE = 43, CURRENT_TIME = 44, ROWNUM = 45;
private final Database database;
private final Session session;
private int[] characterTypes;
private int currentTokenType;
private String currentToken;
private boolean currentTokenQuoted;
private Value currentValue;
private String sqlCommand;
private String originalSQL;
private char[] sqlCommandChars;
private int lastParseIndex;
private int parseIndex;
//private CreateView createView;
private Prepared currentPrepared;
private Select currentSelect;
private ObjectArray<Parameter> parameters;
private String schemaName;
private ObjectArray<String> expectedList;
private boolean rightsChecked;
private boolean recompileAlways;
private ObjectArray<Parameter> indexedParameterList;
public Parser(Session session2) {
this.session = session2;
database = session.getDatabase();
}
/**
* Parse the statement, but don't prepare it for execution.
*
* @param sql the SQL statement to parse
* @return the prepared object
*/
public Prepared parseOnly(String sql) throws SQLException {
return parse(sql);
}
private Prepared parse(String sql) throws SQLException {
Prepared p = null;
// try {
// first, try the fast variant
p = parse(sql, false);
// }// catch (SQLException e) {
// if (e.getErrorCode() == ErrorCode.SYNTAX_ERROR_1) {
// // now, get the detailed exception
// p = parse(sql, true);
// } else {
// throw Message.addSQL(e, sql);
// }
//}
// p.setPrepareAlways(recompileAlways);
// p.setParameterList(parameters);
return p;
}
private Prepared parse(String sql, boolean withExpectedList) throws SQLException {
initialize(sql);
if (withExpectedList) {
//expectedList = ObjectArray.newInstance();
} else {
// expectedList = null;
}
parameters = ObjectArray.newInstance();
currentSelect = null;
currentPrepared = null;
//createView = null;
recompileAlways = false;
//indexedParameterList = null;
read();
return parsePrepared();
}
private Prepared parsePrepared() throws SQLException {
int start = lastParseIndex;
Prepared c = null;
String token = currentToken;
if (token.length() == 0) {
c = new NoOperation();
} else {
char first = token.charAt(0);
switch (first) {
case '(':
c = parseSelect();
break;
case 'A':
if (readIf("ALTER")) {
c = parseAlter();
} else if (readIf("ANALYZE")) {
c = parseAnalyze();
}
break;
case 'F':
if (isToken("FROM")) {
c = parseSelect();
}
break;
case 'I':
if (readIf("INSERT")) {
c = parseInsert();
}
break;
case 'M':
if (readIf("MERGE")) {
c = parseMerge();
}
break;
case 'P':
if (readIf("PREPARE")) {
c = parsePrepare();
}
break;
case 'S':
if (isToken("SELECT")) {
c = parseSelect();
} else if (readIf("SET")) {
c = parseSet();
} else if (readIf("SAVEPOINT")) {
c = parseSavepoint();
} else if (readIf("SCRIPT")) {
c = parseScript();
} else if (readIf("SHUTDOWN")) {
c = parseShutdown();
} else if (readIf("SHOW")) {
c = parseShow();
}
break;
case 'T':
if (readIf("TRUNCATE")) {
c = parseTruncate();
}
break;
case 'U':
if (readIf("UPDATE")) {
c = parseUpdate();
}
break;
case 'V':
if (readIf("VALUES")) {
c = parserCall();
}
break;
case 'W':
if (readIf("WITH")) {
c = parserWith();
}
break;
default:
throw getSyntaxError();
}
if (indexedParameterList != null) {
for (int i = 0; i < indexedParameterList.size(); i++) {
if (indexedParameterList.get(i) == null) {
indexedParameterList.set(i, new Parameter(session, i));
}
}
parameters = indexedParameterList;
}
if (readIf("{")) {
do {
int index = (int) readLong() - 1;
if (index < 0 || index >= parameters.size()) {
throw getSyntaxError();
}
Parameter p = parameters.get(index);
if (p == null) {
throw getSyntaxError();
}
read(":");
Expression expr = readExpression();
// expr = expr.optimize(session);
//p.setValue(expr.getValue(session));
} while (readIf(","));
read("}");
for (Parameter p : parameters) {
//p.checkSet();
}
parameters.clear();
}
}
if (c == null) {
throw getSyntaxError();
}
setSQL(c, null, start);
return c;
}
private SQLException getSyntaxError() {
if (expectedList == null || expectedList.size() == 0) {
return Message.getSyntaxError(sqlCommand, parseIndex);
}
StatementBuilder buff = new StatementBuilder();
for (String e : expectedList) {
buff.appendExceptFirst(", ");
buff.append(e);
}
return Message.getSyntaxError(sqlCommand, parseIndex, buff.toString());
}
private Prepared parseAnalyze() throws SQLException {
// Analyze command = new Analyze(session);
// if (readIf("SAMPLE_SIZE")) {
// command.setTop(getPositiveInt());
// }
// return command;
return null;
}
private Prepared parseShutdown() throws SQLException {
return null;
}
private Prepared parsePrepare() throws SQLException {
return null;
}
private Prepared parseSavepoint() throws SQLException {
return null;
}
private Schema getSchema() throws SQLException {
// if (schemaName == null) {
// return null;
// }
// Schema schema = database.findSchema(schemaName);
// if (schema == null) {
// if ("SESSION".equals(schemaName)) {
// // for local temporary tables
// schema = database.getSchema(session.getCurrentSchemaName());
// } else {
// throw Message.getSQLException(ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
// }
// }
// return schema;
return null;
}
private Column readTableColumn(TableFilter filter) throws SQLException {
// String tableAlias = null;
// String columnName = readColumnIdentifier();
// if (readIf(".")) {
// tableAlias = columnName;
// columnName = readColumnIdentifier();
// if (readIf(".")) {
// String schema = tableAlias;
// tableAlias = columnName;
// columnName = readColumnIdentifier();
// if (readIf(".")) {
// String catalogName = schema;
// schema = tableAlias;
// tableAlias = columnName;
// columnName = readColumnIdentifier();
// if (!catalogName.equals(database.getShortName())) {
// throw Message.getSQLException(ErrorCode.DATABASE_NOT_FOUND_1, catalogName);
// }
// }
// if (!schema.equals(filter.getTable().getSchema().getName())) {
// throw Message.getSQLException(ErrorCode.SCHEMA_NOT_FOUND_1, schema);
// }
// }
// if (!tableAlias.equals(filter.getTableAlias())) {
// throw Message.getSQLException(ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1, tableAlias);
// }
// }
// return filter.getTable().getColumn(columnName);
return null;
}
private Prepared parseUpdate() throws SQLException {
return null;
}
private TableFilter readSimpleTableFilter() throws SQLException {
// Table table = readTableOrView();
// String alias = null;
// if (readIf("AS")) {
// alias = readAliasIdentifier();
// } else if (currentTokenType == IDENTIFIER) {
// if (!"SET".equals(currentToken)) {
// // SET is not a keyword (PostgreSQL supports it as a table name)
// alias = readAliasIdentifier();
// }
// }
// return new TableFilter(session, table, alias, rightsChecked, currentSelect);
return null;
}
private IndexColumn[] parseIndexColumnList() throws SQLException {
// ObjectArray<IndexColumn> columns = ObjectArray.newInstance();
// do {
// IndexColumn column = new IndexColumn();
// column.columnName = readColumnIdentifier();
// columns.add(column);
// if (readIf("ASC")) {
// // ignore
// } else if (readIf("DESC")) {
// column.sortType = SortOrder.DESCENDING;
// }
// if (readIf("NULLS")) {
// if (readIf("FIRST")) {
// column.sortType |= SortOrder.NULLS_FIRST;
// } else {
// read("LAST");
// column.sortType |= SortOrder.NULLS_LAST;
// }
// }
// } while (readIf(","));
// read(")");
// return columns.toArray(new IndexColumn[columns.size()]);
return null;
}
private String[] parseColumnList() throws SQLException {
ObjectArray<String> columns = ObjectArray.newInstance();
do {
String columnName = readColumnIdentifier();
columns.add(columnName);
} while (readIfMore());
return columns.toArray(new String[columns.size()]);
}
private Column[] parseColumnList(Table table) throws SQLException {
// ObjectArray<Column> columns = ObjectArray.newInstance();
// HashSet<Column> set = New.hashSet();
// if (!readIf(")")) {
// do {
// Column column = table.getColumn(readColumnIdentifier());
// if (!set.add(column)) {
// throw Message.getSQLException(ErrorCode.DUPLICATE_COLUMN_NAME_1, column.getSQL());
// }
// columns.add(column);
// } while (readIfMore());
// }
// return columns.toArray(new Column[columns.size()]);
return null;
}
private boolean readIfMore() throws SQLException {
if (readIf(",")) {
return !readIf(")");
}
read(")");
return false;
}
private Prepared parseHelp() throws SQLException {
return null;
}
private Prepared parseShow() throws SQLException {
return null;
// ObjectArray<Value> paramValues = ObjectArray.newInstance();
// StringBuilder buff = new StringBuilder("SELECT ");
// if (readIf("CLIENT_ENCODING")) {
// // for PostgreSQL compatibility
// buff.append("'UNICODE' AS CLIENT_ENCODING FROM DUAL");
// } else if (readIf("DATESTYLE")) {
// // for PostgreSQL compatibility
// buff.append("'ISO' AS DATESTYLE FROM DUAL");
// } else if (readIf("SERVER_VERSION")) {
// // for PostgreSQL compatibility
// buff.append("'8.1.4' AS SERVER_VERSION FROM DUAL");
// } else if (readIf("SERVER_ENCODING")) {
// // for PostgreSQL compatibility
// buff.append("'UTF8' AS SERVER_ENCODING FROM DUAL");
// } else if (readIf("TABLES")) {
// // for MySQL compatibility
// String schema = Constants.SCHEMA_MAIN;
// if (readIf("FROM")) {
// schema = readUniqueIdentifier();
// }
// buff.append("TABLE_NAME, TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=? ORDER BY TABLE_NAME");
// paramValues.add(ValueString.get(schema));
// } else if (readIf("COLUMNS")) {
// // for MySQL compatibility
// read("FROM");
// String tableName = readUniqueIdentifier();
// paramValues.add(ValueString.get(tableName));
// String schema = Constants.SCHEMA_MAIN;
// if (readIf("FROM")) {
// schema = readUniqueIdentifier();
// }
// buff.append("C.COLUMN_NAME FIELD, " +
// "C.TYPE_NAME || '(' || C.NUMERIC_PRECISION || ')' TYPE, " +
// "C.IS_NULLABLE \"NULL\", " +
// "CASE I.INDEX_TYPE_NAME WHEN 'PRIMARY KEY' THEN 'PRI' WHEN 'UNIQUE INDEX' THEN 'UNI' ELSE '' END KEY, " +
// "IFNULL(COLUMN_DEFAULT, 'NULL') DEFAULT " +
// "FROM INFORMATION_SCHEMA.COLUMNS C LEFT OUTER JOIN INFORMATION_SCHEMA.INDEXES I " +
// "ON I.TABLE_SCHEMA=C.TABLE_SCHEMA " +
// "AND I.TABLE_NAME=C.TABLE_NAME " +
// "AND I.COLUMN_NAME=C.COLUMN_NAME " +
// "WHERE C.TABLE_NAME=? AND C.TABLE_SCHEMA=? " +
// "ORDER BY C.ORDINAL_POSITION");
// //paramValues.add(ValueString.get(schema));
// } else if (readIf("DATABASES") || readIf("SCHEMAS")) {
// // for MySQL compatibility
// buff.append("SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA");
// }
// return prepare(session, buff.toString(), paramValues);
}
private Prepared parseMerge() throws SQLException {
return null;
}
private Prepared parseInsert() throws SQLException {
return null;
}
private TableFilter readTableFilter(boolean fromOuter) throws SQLException {
Table table;
String alias = null;
// if (readIf("(")) {
// if (isToken("SELECT") || isToken("FROM")) {
// int start = lastParseIndex;
// int paramIndex = parameters.size();
// Query query = parseSelectUnion();
// read(")");
// query = parseSelectUnionExtension(query, start, true);
// ObjectArray<Parameter> params = ObjectArray.newInstance();
// for (int i = paramIndex; i < parameters.size(); i++) {
// params.add(parameters.get(i));
// }
// query.setParameterList(params);
// query.init();
// Session s;
// if (createView != null) {
// s = database.getSystemSession();
// } else {
// s = session;
// }
// alias = session.getNextSystemIdentifier(sqlCommand);
// table = TableView.createTempView(s, session.getUser(), alias, query, currentSelect);
// } else {
// TableFilter top = readTableFilter(fromOuter);
// top = readJoin(top, currentSelect, fromOuter);
// read(")");
// alias = readFromAlias(null);
// if (alias != null) {
// top.setAlias(alias);
// }
// return top;
// }
// } else {
String tableName = readIdentifierWithSchema(null);
// if (readIf("(")) {
// Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
// if (tableName.equals(RangeTable.NAME)) {
// Expression min = readExpression();
// read(",");
// Expression max = readExpression();
// read(")");
// table = new RangeTable(mainSchema, min, max);
// } else {
// Expression func = readFunction(tableName);
// if (!(func instanceof FunctionCall)) {
// throw getSyntaxError();
// }
// table = new FunctionTable(mainSchema, session, func, (FunctionCall) func);
// }
// } else if ("DUAL".equals(tableName)) {
// table = getDualTable();
// } else {
table = readTableOrView(tableName);
// }
// }
alias = readFromAlias(alias);
return new TableFilter(session, table, alias, currentSelect);
}
private String readFromAlias(String alias) throws SQLException {
if (readIf("AS")) {
alias = readAliasIdentifier();
} else if (currentTokenType == IDENTIFIER) {
// left and right are not keywords (because they are functions as
// well)
if (!isToken("LEFT") && !isToken("RIGHT") && !isToken("FULL")) {
alias = readAliasIdentifier();
}
}
return alias;
}
private Prepared parseTruncate() throws SQLException {
return null;
}
private boolean readIfExists(boolean ifExists) throws SQLException {
if (readIf("IF")) {
read("EXISTS");
ifExists = true;
}
return ifExists;
}
private Prepared parseComment() throws SQLException {
return null;
}
private Prepared parseDropUserDataType() throws SQLException {
return null;
}
private Prepared parseDropAggregate() throws SQLException {
return null;
}
private TableFilter readJoin(TableFilter top, Select command, boolean fromOuter) throws SQLException {
TableFilter last = top;
while (true) {
if (readIf("RIGHT")) {
readIf("OUTER");
read("JOIN");
// the right hand side is the 'inner' table usually
TableFilter newTop = readTableFilter(fromOuter);
newTop = readJoin(newTop, command, true);
Expression on = null;
if (readIf("ON")) {
on = readExpression();
}
newTop.addJoin(top, true, on);
top = newTop;
last = newTop;
} else if (readIf("LEFT")) {
readIf("OUTER");
read("JOIN");
TableFilter join = readTableFilter(true);
top = readJoin(top, command, true);
Expression on = null;
if (readIf("ON")) {
on = readExpression();
}
top.addJoin(join, true, on);
last = join;
} else if (readIf("FULL")) {
throw this.getSyntaxError();
} else if (readIf("INNER")) {
read("JOIN");
TableFilter join = readTableFilter(fromOuter);
top = readJoin(top, command, false);
Expression on = null;
if (readIf("ON")) {
on = readExpression();
}
top.addJoin(join, fromOuter, on);
last = join;
} else if (readIf("JOIN")) {
TableFilter join = readTableFilter(fromOuter);
top = readJoin(top, command, false);
Expression on = null;
if (readIf("ON")) {
on = readExpression();
}
top.addJoin(join, fromOuter, on);
last = join;
} else if (readIf("CROSS")) {
read("JOIN");
TableFilter join = readTableFilter(fromOuter);
top.addJoin(join, fromOuter, null);
last = join;
} else if (readIf("NATURAL")) {
read("JOIN");
TableFilter join = readTableFilter(fromOuter);
Column[] tableCols = last.getTable().getColumns().toArray(new Column[0]);
Column[] joinCols = join.getTable().getColumns().toArray(new Column[0]);
String tableSchema = last.getTable().getSchema().getName();
String joinSchema = join.getTable().getSchema().getName();
Expression on = null;
for (Column tc : tableCols) {
String tableColumnName = tc.getName();
for (Column c : joinCols) {
String joinColumnName = c.getName();
if (tableColumnName.equals(joinColumnName)) {
// XXX join.addNaturalJoinColumn(c);
Expression tableExpr = new ExpressionColumn(session, tableSchema, last
.getTableAlias(), tableColumnName);
Expression joinExpr = new ExpressionColumn(session, joinSchema, join
.getTableAlias(), joinColumnName);
Expression equal = new Comparison(session, Operator.EQUAL, tableExpr, joinExpr);
if (on == null) {
on = equal;
} else {
on = new ConditionAndOr(session, ConditionAndOr.AND, on, equal);
}
}
}
}
top.addJoin(join, fromOuter, on);
last = join;
} else {
break;
}
}
return top;
}
private Query parseSelect() throws SQLException {
// int paramIndex = parameters.size();
Query command = parseSelectUnion();
// ObjectArray<Parameter> params = ObjectArray.newInstance();
// for (int i = paramIndex; i < parameters.size(); i++) {
// params.add(parameters.get(i));
// }
// command.setParameterList(params);
// command.init();
return command;
}
private Query parseSelectUnion() throws SQLException {
int start = lastParseIndex;
Query command = parseSelectSub();
return parseSelectUnionExtension(command, start, false);
}
private Query parseSelectUnionExtension(Query command, int start, boolean unionOnly) throws SQLException {
while (true) {
if (readIf("UNION")) {
SelectUnion union = new SelectUnion(session, command);
if (readIf("ALL")) {
union.setUnionType(SelectUnion.UNION_ALL);
} else {
readIf("DISTINCT");
union.setUnionType(SelectUnion.UNION);
}
union.setRight(parseSelectSub());
command = union;
} else if (readIf("MINUS") || readIf("EXCEPT")) {
SelectUnion union = new SelectUnion(session, command);
union.setUnionType(SelectUnion.EXCEPT);
union.setRight(parseSelectSub());
command = union;
} else if (readIf("INTERSECT")) {
SelectUnion union = new SelectUnion(session, command);
union.setUnionType(SelectUnion.INTERSECT);
union.setRight(parseSelectSub());
command = union;
} else {
break;
}
}
if (!unionOnly) {
parseEndOfQuery(command);
}
setSQL(command, null, start);
return command;
}
private void parseEndOfQuery(Prepared command) throws SQLException {
//
// if (readIf("ORDER")) {
// read("BY");
// Select oldSelect = currentSelect;
// if (command instanceof Select) {
// currentSelect = (Select) command;
// }
// ObjectArray<SelectOrderBy> orderList = ObjectArray.newInstance();
// do {
// boolean canBeNumber = true;
// if (readIf("=")) {
// canBeNumber = false;
// }
// SelectOrderBy order = new SelectOrderBy();
// Expression expr = readExpression();
// if (canBeNumber && expr instanceof ValueExpression && expr.getType() == Value.INT) {
// order.columnIndexExpr = expr;
// } else if (expr instanceof Parameter) {
// recompileAlways = true;
// order.columnIndexExpr = expr;
// } else {
// order.expression = expr;
// }
// if (readIf("DESC")) {
// order.descending = true;
// } else {
// readIf("ASC");
// }
// if (readIf("NULLS")) {
// if (readIf("FIRST")) {
// order.nullsFirst = true;
// } else {
// read("LAST");
// order.nullsLast = true;
// }
// }
// orderList.add(order);
// } while (readIf(","));
// command.setOrder(orderList);
// currentSelect = oldSelect;
// }
// if (database.getMode().supportOffsetFetch) {
// // make sure aggregate functions will not work here
// Select temp = currentSelect;
// currentSelect = null;
//
// // http://sqlpro.developpez.com/SQL2008/
// if (readIf("OFFSET")) {
// command.setOffset(readExpression().optimize(session));
// if (!readIf("ROW")) {
// read("ROWS");
// }
// }
// if (readIf("FETCH")) {
// read("FIRST");
// if (readIf("ROW")) {
// command.setLimit(ValueExpression.get(ValueInt.get(1)));
// } else {
// Expression limit = readExpression().optimize(session);
// command.setLimit(limit);
// if (!readIf("ROW")) {
// read("ROWS");
// }
// }
// read("ONLY");
// }
//
// currentSelect = temp;
// }
// if (readIf("LIMIT")) {
// Select temp = currentSelect;
// // make sure aggregate functions will not work here
// currentSelect = null;
// Expression limit = readExpression().optimize(session);
// command.setLimit(limit);
// if (readIf("OFFSET")) {
// Expression offset = readExpression().optimize(session);
// command.setOffset(offset);
// } else if (readIf(",")) {
// // MySQL: [offset, ] rowcount
// Expression offset = limit;
// limit = readExpression().optimize(session);
// command.setOffset(offset);
// command.setLimit(limit);
// }
// if (readIf("SAMPLE_SIZE")) {
// command.setSampleSize(getPositiveInt());
// }
// currentSelect = temp;
// }
// if (readIf("FOR")) {
// if (readIf("UPDATE")) {
// if (readIf("OF")) {
// do {
// readIdentifierWithSchema();
// } while (readIf(","));
// } else if (readIf("NOWAIT")) {
// // TOxDO parser: select for update nowait: should not wait
// } else if (readIf("WITH")) {
// // Hibernate / Derby support
// read("RR");
// }
// command.setForUpdate(true);
// } else if (readIf("READ")) {
// read("ONLY");
// if (readIf("WITH")) {
// read("RS");
// }
// }
// }
}
private Query parseSelectSub() throws SQLException {
if (readIf("(")) {
Query command = parseSelectUnion();
read(")");
return command;
}
Select select = parseSelectSimple();
return select;
}
private void parseSelectSimpleFromPart(Select command) throws SQLException {
do {
TableFilter filter = readTableFilter(false);
parseJoinTableFilter(filter, command);
} while (readIf(","));
}
private void parseJoinTableFilter(TableFilter top, Select command) throws SQLException {
top = readJoin(top, command, top.isJoinOuter());
command.addTableFilter(top, true);
boolean isOuter = false;
while (true) {
TableFilter join = top.getJoin();
if (join == null) {
break;
}
isOuter = isOuter | join.isJoinOuter();
if (isOuter) {
command.addTableFilter(join, false);
} else {
// make flat so the optimizer can work better
//Expression on = join.getJoinCondition();
//if (on != null) {
// command.addCondition(on);
//}
//join.removeJoinCondition();
// top.removeJoin();
command.addTableFilter(join, true);
}
top = join;
}
}
private void parseSelectSimpleSelectPart(Select command) throws SQLException {
Select temp = currentSelect;
// make sure aggregate functions will not work in TOP and LIMIT
currentSelect = null;
if (readIf("TOP")) {
// can't read more complex expressions here because
// SELECT TOP 1 +? A FROM TEST could mean
// SELECT TOP (1+?) A FROM TEST or
// SELECT TOP 1 (+?) AS A FROM TEST
// Expression limit = readTerm().optimize(session);
// command.setLimit(limit);
} else if (readIf("LIMIT")) {
// Expression offset = readTerm().optimize(session);
// command.setOffset(offset);
// Expression limit = readTerm().optimize(session);
// command.setLimit(limit);
}
currentSelect = temp;
if (readIf("DISTINCT")) {
// command.setDistinct(true);
} else {
readIf("ALL");
}
ObjectArray<Expression> expressions = ObjectArray.newInstance();
do {
if (readIf("*")) {
// expressions.add(new Wildcard(null, null));
} else {
Expression expr = readExpression();
if (readIf("AS") || currentTokenType == IDENTIFIER) {
String alias = readAliasIdentifier();
// expr = new Alias(expr, alias, database.getMode().aliasColumnName);
}
expressions.add(expr);
}
} while (readIf(","));
command.setExpressions(expressions);
}
private Select parseSelectSimple() throws SQLException {
boolean fromFirst;
if (readIf("SELECT")) {
fromFirst = false;
} else if (readIf("FROM")) {
fromFirst = true;
} else {
throw getSyntaxError();
}
Select command = new Select(session);
int start = lastParseIndex;
Select oldSelect = currentSelect;
currentSelect = command;
currentPrepared = command;
if (fromFirst) {
parseSelectSimpleFromPart(command);
read("SELECT");
parseSelectSimpleSelectPart(command);
} else {
parseSelectSimpleSelectPart(command);
if (!readIf("FROM")) {
// select without FROM: convert to SELECT ... FROM
// SYSTEM_RANGE(1,1)
Table dual = getDualTable();
TableFilter filter = new TableFilter(session, dual, null, currentSelect);
command.addTableFilter(filter, true);
} else {
// Window.alert("parseSelectSimple D");
parseSelectSimpleFromPart(command);
// Window.alert("parseSelectSimple E");
}
}
// Window.alert("parseSelectSimple F" + command);
if (readIf("WHERE")) {
Expression condition = readExpression();
command.addCondition(condition);
}
// Window.alert("parseSelectSimple G" + command);
// the group by is read for the outer select (or not a select)
// so that columns that are not grouped can be used
currentSelect = oldSelect;
if (readIf("GROUP")) {
read("BY");
ObjectArray<Expression> list = ObjectArray.newInstance();
do {
Expression expr = readExpression();
list.add(expr);
} while (readIf(","));
command.setGroupBy(list);
}
currentSelect = command;
if (readIf("HAVING")) {
Expression condition = readExpression();
command.setHaving(condition);
}
// TODO 97 command.setParameterList(parameters);
currentSelect = oldSelect;
setSQL(command, "SELECT", start);
return command;
}
private Table getDualTable() throws SQLException {
return null;
// Schema main = database.findSchema(Constants.SCHEMA_MAIN);
// Expression one = ValueExpression.get(ValueLong.get(1));
// return new RangeTable(main, one, one);
}
private void setSQL(Prepared command, String start, int startIndex) {
String sql = originalSQL.substring(startIndex, lastParseIndex).trim();
if (start != null) {
sql = start + " " + sql;
}
//command.setSQL(sql);
}
private Expression readExpression() throws SQLException {
Expression r = readAnd();
while (readIf("OR")) {
r = new ConditionAndOr(session, ConditionAndOr.OR, r, readAnd());
}
return r;
}
private Expression readAnd() throws SQLException {
Expression r = readCondition();
while (readIf("AND")) {
r = new ConditionAndOr(session, ConditionAndOr.AND, r, readCondition());
}
return r;
}
private Expression readCondition() throws SQLException {
// // TOxDO parser: should probably use switch case for performance
// if (readIf("NOT")) {
// return new ConditionNot(readCondition());
// }
// if (readIf("EXISTS")) {
// read("(");
// Query query = parseSelect();
// // can not reduce expression because it might be a union except
// // query with distinct
// read(")");
// return new ConditionExists(query);
// }
Expression r = readConcat();
while (true) {
// // special case: NOT NULL is not part of an expression (as in CREATE
// // TABLE TEST(ID INT DEFAULT 0 NOT NULL))
// int backup = parseIndex;
boolean not = false;
if (readIf("NOT")) {
not = true;
// if (isToken("NULL")) {
// // this really only works for NOT NULL!
// parseIndex = backup;
// currentToken = "NOT";
// break;
// }
}
Operator op = readCustom(not);
if (op != null) {
Expression b;
switch (op.getCardinality()) {
case ZERO: {
b = null;
break;
}
case ONE: {
b = readConcat();
break;
}
case MULTI: {
read("(");
Collection<Expression> v = new ArrayList<Expression>();
Expression last;
do {
last = readExpression();
v.add(last);
} while (readIf(","));
read(")");
b = new Parameter(session, v);
break;
}
default:
throw new IllegalArgumentException("Can't handle "
+ op.getCardinality());
}
Expression esc = null;
if (readIf("ESCAPE")) {
esc = readConcat();
}
recompileAlways = true;
r = new Comparison(session, op.getName(), r, b);
} //else if (readIf("REGEXP")) {
// Expression b = readConcat();
// r = new CompareLike(database.getCompareMode(), r, b, null, true);
// } else
if (readIf("IS")) {
String type;
if (readIf("NOT")) {
type = Operator.IS_NOT_NULL;
} else {
type = Operator.IS_NULL;
}
read("NULL");
r = new Comparison(session, type, r, null);
// } else if (readIf("IN")) {
// if (SysProperties.OPTIMIZE_IN && !SysProperties.OPTIMIZE_IN_LIST) {
// recompileAlways = true;
// }
// read("(");
// if (readIf(")")) {
// r = ValueExpression.get(ValueBoolean.get(false));
// } else {
// if (isToken("SELECT") || isToken("FROM")) {
// Query query = parseSelect();
// r = new ConditionInSelect(database, r, query, false, Comparison.EQUAL);
// } else {
// ObjectArray<Expression> v = ObjectArray.newInstance();
// Expression last;
// do {
// last = readExpression();
// v.add(last);
// } while (readIf(","));
// if (v.size() == 1 && (last instanceof Subquery)) {
// Subquery s = (Subquery) last;
// Query q = s.getQuery();
// r = new ConditionInSelect(database, r, q, false, Comparison.EQUAL);
// } else {
// r = new ConditionIn(database, r, v);
// }
// }
// read(")");
// }
// } else if (readIf("BETWEEN")) {
// Expression low = readConcat();
// read("AND");
// Expression high = readConcat();
// Expression condLow = new Comparison(session, Comparison.SMALLER_EQUAL, low, r);
// Expression condHigh = new Comparison(session, Comparison.BIGGER_EQUAL, high, r);
// r = new ConditionAndOr(ConditionAndOr.AND, condLow, condHigh);
} else {
String compareType = getCompareType(currentTokenType);
if (compareType == null) {
break;
}
read();
// if (readIf("ALL")) {
// read("(");
// Query query = parseSelect();
// r = new ConditionInSelect(database, r, query, true, compareType);
// read(")");
// } else if (readIf("ANY") || readIf("SOME")) {
// read("(");
// Query query = parseSelect();
// r = new ConditionInSelect(database, r, query, false, compareType);
// read(")");
// } else {
Expression right = readConcat();
// if (readIf("(") && readIf("+") && readIf(")")) {
// // support for a subset of old-fashioned Oracle outer
// // join with (+)
// if (r instanceof ExpressionColumn && right instanceof ExpressionColumn) {
// ExpressionColumn leftCol = (ExpressionColumn) r;
// ExpressionColumn rightCol = (ExpressionColumn) right;
// ObjectArray<TableFilter> filters = currentSelect.getTopFilters();
// for (TableFilter f : filters) {
// while (f != null) {
// leftCol.mapColumns(f, 0);
// rightCol.mapColumns(f, 0);
// f = f.getJoin();
// }
// }
// TableFilter leftFilter = leftCol.getTableFilter();
// TableFilter rightFilter = rightCol.getTableFilter();
// r = new Comparison(session, compareType, r, right);
// if (leftFilter != null && rightFilter != null) {
// int idx = filters.indexOf(rightFilter);
// if (idx >= 0) {
// filters.remove(idx);
// leftFilter.addJoin(rightFilter, true, r);
// } else {
// rightFilter.mapAndAddFilter(r);
// }
// r = ValueExpression.get(ValueBoolean.get(true));
// }
// }
// } else {
r = new Comparison(session, compareType, r, right);
// }
// }
//if (not) {
// r = new ConditionNot(session, r);
//}
}
}
return r;
}
private Expression readConcat() throws SQLException {
Expression r = readSum();
return r;
// while (true) {
// if (readIf("||")) {
// r = new Operation(Operation.CONCAT, r, readSum());
// } else if (readIf("~")) {
// if (readIf("*")) {
// Function function = Function.getFunction(database, "CAST");
// function.setDataType(new Column("X", Value.STRING_IGNORECASE));
// function.setParameter(0, r);
// r = function;
// }
// r = new CompareLike(database.getCompareMode(), r, readSum(), null, true);
// } else if (readIf("!~")) {
// if (readIf("*")) {
// Function function = Function.getFunction(database, "CAST");
// function.setDataType(new Column("X", Value.STRING_IGNORECASE));
// function.setParameter(0, r);
// r = function;
// }
// r = new ConditionNot(new CompareLike(null, r, readSum(), null, true));
// } else {
// return r;
// }
// }
}
private Expression readSum() throws SQLException {
Expression r = readFactor();
// while (true) {
// if (readIf("+")) {
// r = new Operation(Operation.PLUS, r, readFactor());
// } else if (readIf("-")) {
// r = new Operation(Operation.MINUS, r, readFactor());
// } else {
return r;
// }
// }
}
private Expression readFactor() throws SQLException {
Expression r = readTerm();
// while (true) {
// if (readIf("*")) {
// r = new Operation(Operation.MULTIPLY, r, readTerm());
// } else if (readIf("/")) {
// r = new Operation(Operation.DIVIDE, r, readTerm());
// } else {
return r;
// }
// }
}
private Expression readAggregate(int aggregateType) throws SQLException {
return null;
// if (currentSelect == null) {
// throw getSyntaxError();
// }
// currentSelect.setGroupQuery();
// Expression r;
// if (aggregateType == Aggregate.COUNT) {
// if (readIf("*")) {
// r = new Aggregate(Aggregate.COUNT_ALL, null, currentSelect, false);
// } else {
// boolean distinct = readIf("DISTINCT");
// Expression on = readExpression();
// if (on instanceof Wildcard && !distinct) {
// // PostgreSQL compatibility: count(t.*)
// r = new Aggregate(Aggregate.COUNT_ALL, null, currentSelect, false);
// } else {
// r = new Aggregate(Aggregate.COUNT, on, currentSelect, distinct);
// }
// }
// } else if (aggregateType == Aggregate.GROUP_CONCAT) {
// boolean distinct = readIf("DISTINCT");
// Aggregate agg = new Aggregate(Aggregate.GROUP_CONCAT, readExpression(), currentSelect, distinct);
// if (readIf("ORDER")) {
// read("BY");
// agg.setOrder(parseSimpleOrderList());
// }
// if (readIf("SEPARATOR")) {
// agg.setSeparator(readExpression());
// }
// r = agg;
// } else {
// boolean distinct = readIf("DISTINCT");
// r = new Aggregate(aggregateType, readExpression(), currentSelect, distinct);
// }
// read(")");
// return r;
}
private ObjectArray<Object> parseSimpleOrderList() throws SQLException {
// ObjectArray<SelectOrderBy> orderList = ObjectArray.newInstance();
// do {
// SelectOrderBy order = new SelectOrderBy();
// Expression expr = readExpression();
// order.expression = expr;
// if (readIf("DESC")) {
// order.descending = true;
// } else {
// readIf("ASC");
// }
// orderList.add(order);
// } while (readIf(","));
// return orderList;
return null;
}
private Expression readFunction(String name) throws SQLException {
return null;
// int agg = Aggregate.getAggregateType(name);
// if (agg >= 0) {
// return readAggregate(agg);
// }
// Function function = Function.getFunction(database, name);
// if (function == null) {
// UserAggregate aggregate = database.findAggregate(name);
// if (aggregate != null) {
// return readJavaAggregate(aggregate);
// }
// return readJavaFunction(name);
// }
// switch (function.getFunctionType()) {
// case Function.CAST: {
// function.setParameter(0, readExpression());
// read("AS");
// Column type = parseColumn(null);
// function.setDataType(type);
// read(")");
// break;
// }
// case Function.CONVERT: {
// function.setParameter(0, readExpression());
// read(",");
// Column type = parseColumn(null);
// function.setDataType(type);
// read(")");
// break;
// }
// case Function.EXTRACT: {
// function.setParameter(0, ValueExpression.get(ValueString.get(currentToken)));
// read();
// read("FROM");
// function.setParameter(1, readExpression());
// read(")");
// break;
// }
// case Function.DATE_DIFF: {
// if (Function.isDatePart(currentToken)) {
// function.setParameter(0, ValueExpression.get(ValueString.get(currentToken)));
// read();
// } else {
// function.setParameter(0, readExpression());
// }
// read(",");
// function.setParameter(1, readExpression());
// read(",");
// function.setParameter(2, readExpression());
// read(")");
// break;
// }
// case Function.SUBSTRING: {
// function.setParameter(0, readExpression());
// if (!readIf(",")) {
// read("FROM");
// }
// function.setParameter(1, readExpression());
// if (readIf("FOR") || readIf(",")) {
// function.setParameter(2, readExpression());
// }
// read(")");
// break;
// }
// case Function.POSITION: {
// // can't read expression because IN would be read too early
// function.setParameter(0, readConcat());
// if (!readIf(",")) {
// read("IN");
// }
// function.setParameter(1, readExpression());
// read(")");
// break;
// }
// case Function.TRIM: {
// Expression space = null;
// if (readIf("LEADING")) {
// function = Function.getFunction(database, "LTRIM");
// if (!readIf("FROM")) {
// space = readExpression();
// read("FROM");
// }
// } else if (readIf("TRAILING")) {
// function = Function.getFunction(database, "RTRIM");
// if (!readIf("FROM")) {
// space = readExpression();
// read("FROM");
// }
// } else if (readIf("BOTH")) {
// if (!readIf("FROM")) {
// space = readExpression();
// read("FROM");
// }
// }
// Expression p0 = readExpression();
// if (readIf(",")) {
// space = readExpression();
// } else if (readIf("FROM")) {
// space = p0;
// p0 = readExpression();
// }
// function.setParameter(0, p0);
// if (space != null) {
// function.setParameter(1, space);
// }
// read(")");
// break;
// }
// case Function.TABLE:
// case Function.TABLE_DISTINCT: {
// int i = 0;
// ObjectArray<Column> columns = ObjectArray.newInstance();
// do {
// String columnName = readAliasIdentifier();
// Column column = parseColumn(columnName);
// columns.add(column);
// read("=");
// function.setParameter(i, readExpression());
// i++;
// } while (readIf(","));
// read(")");
// TableFunction tf = (TableFunction) function;
// tf.setColumns(columns);
// break;
// }
// default:
// if (!readIf(")")) {
// int i = 0;
// do {
// function.setParameter(i++, readExpression());
// } while (readIf(","));
// read(")");
// }
// }
// function.doneWithParameters();
// return function;
}
private Function readFunctionWithoutParameters(String name) throws SQLException {
// if (readIf("(")) {
// read(")");
// }
// Function function = Function.getFunction(database, name);
// function.doneWithParameters();
// return function;
return null;
}
private Expression readWildcardOrSequenceValue(String schema, String objectName) throws SQLException {
// if (readIf("*")) {
// return new Wildcard(schema, objectName);
// }
// if (schema == null) {
// schema = session.getCurrentSchemaName();
// }
// if (readIf("NEXTVAL")) {
// Sequence sequence = findSequence(schema, objectName);
// if (sequence != null) {
// return new SequenceValue(sequence);
// }
// } else if (readIf("CURRVAL")) {
// Sequence sequence = findSequence(schema, objectName);
// if (sequence != null) {
// Function function = Function.getFunction(database, "CURRVAL");
// function.setParameter(0, ValueExpression.get(ValueString.get(sequence.getSchema().getName())));
// function.setParameter(1, ValueExpression.get(ValueString.get(sequence.getName())));
// function.doneWithParameters();
// return function;
// }
// }
return null;
}
private Expression readTermObjectDot(String objectName) throws SQLException {
// Expression expr = readWildcardOrSequenceValue(null, objectName);
// if (expr != null) {
// return expr;
// }
String name = readColumnIdentifier();
// if (readIf(".")) {
// String schema = objectName;
// objectName = name;
// expr = readWildcardOrSequenceValue(schema, objectName);
// if (expr != null) {
// return expr;
// }
// name = readColumnIdentifier();
// if (readIf(".")) {
// String databaseName = schema;
// if (!database.getShortName().equals(databaseName)) {
// throw Message.getSQLException(ErrorCode.DATABASE_NOT_FOUND_1, databaseName);
// }
// schema = objectName;
// objectName = name;
// expr = readWildcardOrSequenceValue(schema, objectName);
// if (expr != null) {
// return expr;
// }
// name = readColumnIdentifier();
// return new ExpressionColumn(database, schema, objectName, name);
// }
// return new ExpressionColumn(database, schema, objectName, name);
// }
return new ExpressionColumn(session, null, objectName, name);
}
private Expression readTerm() throws SQLException {
Expression r = null;
switch (currentTokenType) {
// case AT:
// read();
// r = new Variable(session, readAliasIdentifier());
// if (readIf(":=")) {
// Expression value = readExpression();
// Function function = Function.getFunction(database, "SET");
// function.setParameter(0, r);
// function.setParameter(1, value);
// r = function;
// }
// break;
case PARAMETER:
// there must be no space between ? and the number
boolean indexed = Character.isDigit(sqlCommandChars[parseIndex]);
read();
Parameter p;
// if (indexed && currentTokenType == VALUE && currentValue.getType() == Value.INT) {
// if (indexedParameterList == null) {
// if (parameters == null) {
// // this can occur when parsing expressions only (for example check constraints)
// throw getSyntaxError();
// } else if (parameters.size() > 0) {
// throw Message.getSQLException(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
// }
// indexedParameterList = ObjectArray.newInstance();
// }
// int index = 0;//currentValue.getInt() - 1;
// if (index < 0 || index >= Constants.MAX_PARAMETER_INDEX) {
// throw Message.getInvalidValueException("" + index, "Parameter Index");
// }
// if (indexedParameterList.size() <= index) {
// indexedParameterList.setSize(index + 1);
// }
// p = indexedParameterList.get(index);
// if (p == null) {
// p = new Parameter(index);
// indexedParameterList.set(index, p);
// }
// read();
// } else {
// if (indexedParameterList != null) {
// throw Message.getSQLException(ErrorCode.CANNOT_MIX_INDEXED_AND_UNINDEXED_PARAMS);
// }
p = new Parameter(session, parameters.size());
// }
parameters.add(p);
r = p;
break;
// case KEYWORD:
// if (isToken("SELECT") || isToken("FROM")) {
// Query query = parseSelect();
// r = new Subquery(query);
// } else {
// throw getSyntaxError();
// }
// break;
case IDENTIFIER:
String name = currentToken;
// if (currentTokenQuoted) {
// read();
// if (readIf("(")) {
// r = readFunction(name);
// } else if (readIf(".")) {
// r = readTermObjectDot(name);
// } else {
// r = new ExpressionColumn(database, null, null, name);
// }
// } else {
read();
// if ("X".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
// read();
// // byte[] buffer = ByteUtils.convertStringToBytes(currentValue.getString());
// r = null;//ValueExpression.get(ValueBytes.getNoCopy(buffer));
// } else
if (readIf(".")) {
r = readTermObjectDot(name);
// } else if ("CASE".equals(name)) {
// // CASE must be processed before (,
// // otherwise CASE(3) would be a function call, which it is
// // not
// if (isToken("WHEN")) {
// r = readWhen(null);
// } else {
// Expression left = readExpression();
// r = readWhen(left);
// }
// } else if (readIf("(")) {
// r = readFunction(name);
// } else if ("CURRENT_USER".equals(name)) {
// r = readFunctionWithoutParameters("USER");
// } else if ("CURRENT".equals(name)) {
// if (readIf("TIMESTAMP")) {
// r = readFunctionWithoutParameters("CURRENT_TIMESTAMP");
// } else if (readIf("TIME")) {
// r = readFunctionWithoutParameters("CURRENT_TIME");
// } else if (readIf("DATE")) {
// r = readFunctionWithoutParameters("CURRENT_DATE");
// } else {
// r = new ExpressionColumn(database, null, null, name);
// }
// } else if ("NEXT".equals(name) && readIf("VALUE")) {
// read("FOR");
// Sequence sequence = readSequence();
// r = new SequenceValue(sequence);
// } else if ("DATE".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
// String date = currentValue.getString();
// read();
// //r = ValueExpression.get(ValueDate.get(ValueDate.parseDate(date)));
// } else if ("TIME".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
// String time = currentValue.getString();
// read();
// // r = ValueExpression.get(ValueTime.get(ValueTime.parseTime(time)));
// } else if ("TIMESTAMP".equals(name) && currentTokenType == VALUE
// && currentValue.getType() == Value.STRING) {
// String timestamp = currentValue.getString();
// read();
// //r = ValueExpression.get(ValueTimestamp.getNoCopy(ValueTimestamp.parseTimestamp(timestamp)));
// } else if ("E".equals(name) && currentTokenType == VALUE && currentValue.getType() == Value.STRING) {
// String text = currentValue.getString();
// read();
// r = ValueExpression.get(ValueString.get(text));
} else {
r = new ExpressionColumn(session, null, null, name);
}
// }
break;
// case MINUS:
// read();
// if (currentTokenType == VALUE) {
// //r = ValueExpression.get(currentValue.negate());
// // convert Integer.MIN_VALUE to int (-Integer.MIN_VALUE needed
// // to be a long)
// // if (r.getType() == Value.LONG && r.getValue(session).getLong() == Integer.MIN_VALUE) {
// // r = ValueExpression.get(ValueInt.get(Integer.MIN_VALUE));
// //}
// read();
// } else {
// r = new Operation(Operation.NEGATE, readTerm(), null);
// }
// break;
// case PLUS:
// read();
// r = readTerm();
// break;
case OPEN:
read();
r = readExpression();
if (readIf(",")) {
ObjectArray<Expression> list = ObjectArray.newInstance();
list.add(r);
do {
r = readExpression();
list.add(r);
} while (readIf(","));
Expression[] array = new Expression[list.size()];
list.toArray(array);
// XXX r = new ExpressionList(array);
}
read(")");
break;
// case TRUE:
// read();
// r = ValueExpression.get(ValueBoolean.get(true));
// break;
// case FALSE:
// read();
// r = ValueExpression.get(ValueBoolean.get(false));
// break;
// case CURRENT_TIME:
// read();
// r = readFunctionWithoutParameters("CURRENT_TIME");
// break;
// case CURRENT_DATE:
// read();
// r = readFunctionWithoutParameters("CURRENT_DATE");
// break;
// case CURRENT_TIMESTAMP: {
// Function function = Function.getFunction(database, "CURRENT_TIMESTAMP");
// read();
// if (readIf("(")) {
// if (!readIf(")")) {
// function.setParameter(0, readExpression());
// read(")");
// }
// }
// function.doneWithParameters();
// r = function;
// break;
// }
// case ROWNUM:
// read();
// if (readIf("(")) {
// read(")");
// }
// r = new Rownum(currentSelect == null ? currentPrepared : currentSelect);
// break;
case NULL:
read();
r = new Null();
break;
// case VALUE:
// r = ValueExpression.get(currentValue);
// read();
// break;
default:
throw getSyntaxError();
}
// if (readIf("[")) {
// Function function = Function.getFunction(database, "ARRAY_GET");
// function.setParameter(0, r);
// r = readExpression();
// r = new Operation(Operation.PLUS, r, null);//ValueExpression.get(ValueInt.get(1)));
// function.setParameter(1, r);
// r = function;
// read("]");
// }
// if (readIf("::")) {
// // PostgreSQL compatibility
// Column col = parseColumn(null);
// Function function = Function.getFunction(database, "CAST");
// function.setDataType(col);
// function.setParameter(0, r);
// r = function;
return r;
}
private Expression readWhen(Expression left) throws SQLException {
// if (readIf("END")) {
// readIf("CASE");
// return ValueExpression.getNull();
// }
// if (readIf("ELSE")) {
// Expression elsePart = readExpression();
// read("END");
// readIf("CASE");
// return elsePart;
// }
// readIf("WHEN");
// Expression when = readExpression();
// if (left != null) {
// when = new Comparison(session, Comparison.EQUAL, left, when);
// }
// read("THEN");
// Expression then = readExpression();
// Expression elsePart = readWhen(left);
// Function function = Function.getFunction(session.getDatabase(), "CASEWHEN");
// function.setParameter(0, when);
// function.setParameter(1, then);
// function.setParameter(2, elsePart);
// function.doneWithParameters();
// return function;
return null;
}
private int getPositiveInt() throws SQLException {
return 1;
// int v = getInt();
// if (v < 0) {
// throw Message.getInvalidValueException("" + v, "positive integer");
// }
// return v;
}
private int getInt() throws SQLException {
return 1;
// boolean minus = false;
// if (currentTokenType == MINUS) {
// minus = true;
// read();
// } else if (currentTokenType == PLUS) {
// read();
// }
// if (currentTokenType != VALUE || currentValue.getType() != Value.INT) {
// throw Message.getSyntaxError(sqlCommand, parseIndex, "integer");
// }
// int i = 1;//currentValue.getInt();
// read();
// return minus ? -i : i;
}
private long readLong() throws SQLException {
return 1;
// boolean minus = false;
// if (currentTokenType == MINUS) {
// minus = true;
// read();
// }
// if (currentTokenType != VALUE
// || (currentValue.getType() != Value.INT && currentValue.getType() != Value.DECIMAL)) {
// throw Message.getSyntaxError(sqlCommand, parseIndex, "long");
// }
// long i = 1;//currentValue.getLong();
// read();
// return minus ? -i : i;
}
private String readString() throws SQLException {
// Expression expr = readExpression();
// if (!(expr instanceof ValueExpression)) {
// throw Message.getSyntaxError(sqlCommand, parseIndex, "string");
// }
// String s = expr.getValue(session).getString();
// return s;
return null;
}
private String readIdentifierWithSchema(String defaultSchemaName) throws SQLException {
if (currentTokenType != IDENTIFIER) {
throw Message.getSyntaxError(sqlCommand, parseIndex, "identifier");
}
String s = currentToken;
read();
// schemaName = defaultSchemaName;
// if (readIf(".")) {
// schemaName = s;
// if (currentTokenType != IDENTIFIER) {
// throw Message.getSyntaxError(sqlCommand, parseIndex, "identifier");
// }
// s = currentToken;
// read();
// }
// if (".".equals(currentToken)) {
// if (schemaName.equalsIgnoreCase(database.getShortName())) {
// read(".");
// schemaName = s;
// if (currentTokenType != IDENTIFIER) {
// throw Message.getSyntaxError(sqlCommand, parseIndex, "identifier");
// }
// s = currentToken;
// read();
// }
// }
return s;
}
private String readIdentifierWithSchema() throws SQLException {
return null; //readIdentifierWithSchema(session.getCurrentSchemaName());
}
private String readAliasIdentifier() throws SQLException {
return readColumnIdentifier();
}
private String readUniqueIdentifier() throws SQLException {
return readColumnIdentifier();
}
private String readColumnIdentifier() throws SQLException {
if (currentTokenType != IDENTIFIER) {
throw Message.getSyntaxError(sqlCommand, parseIndex, "identifier");
}
String s = currentToken;
read();
return s;
}
private void read(String expected) throws SQLException {
if (!expected.equals(currentToken) || currentTokenQuoted) {
throw Message.getSyntaxError(sqlCommand, parseIndex, expected);
}
read();
}
private Operator readCustom(boolean not) throws SQLException {
String token = not ? "NOT " + currentToken : currentToken;
Operator op = session.getDatabase().getOperatorByName(token);
if (op != null) {
read();
return op;
}
return null;
}
private boolean readIf(String token) throws SQLException {
if (token.equals(currentToken) && !currentTokenQuoted) {
read();
return true;
}
addExpected(token);
return false;
}
private boolean isToken(String token) {
boolean result = token.equals(currentToken) && !currentTokenQuoted;
if (result) {
return true;
}
addExpected(token);
return false;
}
private void addExpected(String token) {
if (expectedList != null) {
expectedList.add(token);
}
}
private void read() throws SQLException {
currentTokenQuoted = false;
if (expectedList != null) {
expectedList.clear();
}
int[] types = characterTypes;
lastParseIndex = parseIndex;
int i = parseIndex;
int type = types[i];
while (type == 0) {
type = types[++i];
}
int start = i;
char[] chars = sqlCommandChars;
char c = chars[i++];
currentToken = "";
switch (type) {
case CHAR_NAME:
while (true) {
type = types[i];
if (type != CHAR_NAME && type != CHAR_VALUE) {
break;
}
i++;
}
currentToken = sqlCommand.substring(start, i);
currentTokenType = getTokenType(currentToken);
parseIndex = i;
return;
case CHAR_QUOTED: {
String result = null;
while (true) {
for (int begin = i;; i++) {
if (chars[i] == '\"') {
if (result == null) {
result = sqlCommand.substring(begin, i);
} else {
result += sqlCommand.substring(begin - 1, i);
}
break;
}
}
if (chars[++i] != '\"') {
break;
}
i++;
}
currentToken = result;
parseIndex = i;
currentTokenQuoted = true;
currentTokenType = IDENTIFIER;
return;
}
case CHAR_SPECIAL_2:
if (types[i] == CHAR_SPECIAL_2) {
i++;
}
currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken);
parseIndex = i;
return;
case CHAR_SPECIAL_1:
currentToken = sqlCommand.substring(start, i);
currentTokenType = getSpecialType(currentToken);
parseIndex = i;
return;
case CHAR_VALUE:
if (c == '0' && chars[i] == 'X') {
// hex number
long number = 0;
start += 2;
i++;
while (true) {
c = chars[i];
if ((c < '0' || c > '9') && (c < 'A' || c > 'F')) {
checkLiterals(false);
currentValue = null; //ValueInt.get((int) number);
currentTokenType = VALUE;
currentToken = "0";
parseIndex = i;
return;
}
number = (number << 4) + c - (c >= 'A' ? ('A' - 0xa) : ('0'));
if (number > Integer.MAX_VALUE) {
readHexDecimal(start, i);
return;
}
i++;
}
}
long number = c - '0';
while (true) {
c = chars[i];
if (c < '0' || c > '9') {
if (c == '.') {
readDecimal(start, i);
break;
}
if (c == 'E') {
readDecimal(start, i);
break;
}
checkLiterals(false);
currentValue = null; //ValueInt.get((int) number);
currentTokenType = VALUE;
currentToken = "0";
parseIndex = i;
break;
}
number = number * 10 + (c - '0');
if (number > Integer.MAX_VALUE) {
readDecimal(start, i);
break;
}
i++;
}
return;
case CHAR_DECIMAL:
if (types[i] != CHAR_VALUE) {
currentTokenType = KEYWORD;
currentToken = ".";
parseIndex = i;
return;
}
readDecimal(i - 1, i);
return;
case CHAR_STRING: {
String result = null;
while (true) {
for (int begin = i;; i++) {
if (chars[i] == '\'') {
if (result == null) {
result = sqlCommand.substring(begin, i);
} else {
result += sqlCommand.substring(begin - 1, i);
}
break;
}
}
if (chars[++i] != '\'') {
break;
}
i++;
}
currentToken = "'";
checkLiterals(true);
currentValue = null; //ValueString.get(StringCache.getNew(result));
parseIndex = i;
currentTokenType = VALUE;
return;
}
case CHAR_DOLLAR_QUOTED_STRING: {
String result = null;
int begin = i - 1;
while (types[i] == CHAR_DOLLAR_QUOTED_STRING) {
i++;
}
result = sqlCommand.substring(begin, i);
currentToken = "'";
checkLiterals(true);
currentValue = null; //ValueString.get(StringCache.getNew(result));
parseIndex = i;
currentTokenType = VALUE;
return;
}
case CHAR_END:
currentToken = "";
currentTokenType = END;
parseIndex = i;
return;
default:
throw getSyntaxError();
}
}
private void checkLiterals(boolean text) throws SQLException {
// if (!session.getAllowLiterals()) {
// int allowed = database.getAllowLiterals();
// if (allowed == Constants.ALLOW_LITERALS_NONE || (text && allowed != Constants.ALLOW_LITERALS_ALL)) {
// throw Message.getSQLException(ErrorCode.LITERALS_ARE_NOT_ALLOWED);
// }
// }
}
private void readHexDecimal(int start, int i) throws SQLException {
char[] chars = sqlCommandChars;
char c;
do {
c = chars[++i];
} while ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'));
parseIndex = i;
String sub = sqlCommand.substring(start, i);
BigDecimal bd = new BigDecimal(new BigInteger(sub, 16));
checkLiterals(false);
// currentValue = null;//ValueDecimal.get(bd);
currentTokenType = VALUE;
}
private void readDecimal(int start, int i) throws SQLException {
char[] chars = sqlCommandChars;
int[] types = characterTypes;
// go until the first non-number
while (true) {
int t = types[i];
if (t != CHAR_DECIMAL && t != CHAR_VALUE) {
break;
}
i++;
}
if (chars[i] == 'E') {
i++;
if (chars[i] == '+' || chars[i] == '-') {
i++;
}
if (types[i] != CHAR_VALUE) {
throw getSyntaxError();
}
while (types[++i] == CHAR_VALUE) {
// go until the first non-number
}
}
parseIndex = i;
String sub = sqlCommand.substring(start, i);
BigDecimal bd;
try {
bd = new BigDecimal(sub);
} catch (NumberFormatException e) {
throw Message.getSQLException(ErrorCode.DATA_CONVERSION_ERROR_1, e, sub);
}
checkLiterals(false);
currentValue = null; //ValueDecimal.get(bd);
currentTokenType = VALUE;
}
public Session getSession() {
return null;
}
private void initialize(String sql) throws SQLException {
if (sql == null) {
sql = "";
}
originalSQL = sql;
sqlCommand = sql;
int len = sql.length() + 1;
char[] command = new char[len];
int[] types = new int[len];
len--;
sql.getChars(0, len, command, 0);
boolean changed = false;
command[len] = ' ';
int startLoop = 0;
int lastType = 0;
for (int i = 0; i < len; i++) {
char c = command[i];
int type = 0;
switch (c) {
case '/':
if (command[i + 1] == '*') {
// block comment
changed = true;
command[i] = ' ';
command[i + 1] = ' ';
startLoop = i;
i += 2;
checkRunOver(i, len, startLoop);
while (command[i] != '*' || command[i + 1] != '/') {
command[i++] = ' ';
checkRunOver(i, len, startLoop);
}
command[i] = ' ';
command[i + 1] = ' ';
i++;
} else if (command[i + 1] == '/') {
// single line comment
changed = true;
startLoop = i;
while (true) {
c = command[i];
if (c == '\n' || c == '\r' || i >= len - 1) {
break;
}
command[i++] = ' ';
checkRunOver(i, len, startLoop);
}
} else {
type = CHAR_SPECIAL_1;
}
break;
case '-':
if (command[i + 1] == '-') {
// single line comment
changed = true;
startLoop = i;
while (true) {
c = command[i];
if (c == '\n' || c == '\r' || i >= len - 1) {
break;
}
command[i++] = ' ';
checkRunOver(i, len, startLoop);
}
} else {
type = CHAR_SPECIAL_1;
}
break;
case '$':
if (false && command[i + 1] == '$' && (i == 0 || command[i - 1] <= ' ')) {
// dollar quoted string
changed = true;
command[i] = ' ';
command[i + 1] = ' ';
startLoop = i;
i += 2;
checkRunOver(i, len, startLoop);
while (command[i] != '$' || command[i + 1] != '$') {
types[i++] = CHAR_DOLLAR_QUOTED_STRING;
checkRunOver(i, len, startLoop);
}
command[i] = ' ';
command[i + 1] = ' ';
i++;
} else {
if (lastType == CHAR_NAME || lastType == CHAR_VALUE) {
// $ inside an identifier is supported
type = CHAR_NAME;
} else {
// but not at the start, to support PostgreSQL $1
type = CHAR_SPECIAL_1;
}
}
break;
case '(':
case ')':
case '{':
case '}':
case '*':
case ',':
case ';':
case '+':
case '%':
case '?':
case '@':
case ']':
type = CHAR_SPECIAL_1;
break;
case '!':
case '<':
case '>':
case '|':
case '=':
case ':':
case '~':
type = CHAR_SPECIAL_2;
break;
case '.':
type = CHAR_DECIMAL;
break;
case '\'':
type = types[i] = CHAR_STRING;
startLoop = i;
while (command[++i] != '\'') {
checkRunOver(i, len, startLoop);
}
break;
case '[':
if (false) {
// SQL Server alias for "
command[i] = '"';
changed = true;
type = types[i] = CHAR_QUOTED;
startLoop = i;
while (command[++i] != ']') {
checkRunOver(i, len, startLoop);
}
command[i] = '"';
} else {
type = CHAR_SPECIAL_1;
}
break;
case '`':
// MySQL alias for ", but not case sensitive
command[i] = '"';
changed = true;
type = types[i] = CHAR_QUOTED;
startLoop = i;
while (command[++i] != '`') {
checkRunOver(i, len, startLoop);
c = command[i];
command[i] = Character.toUpperCase(c);
}
command[i] = '"';
break;
case '\"':
type = types[i] = CHAR_QUOTED;
startLoop = i;
while (command[++i] != '\"') {
checkRunOver(i, len, startLoop);
}
break;
case '_':
type = CHAR_NAME;
break;
default:
if (c >= 'a' && c <= 'z') {
command[i] = (char) (c - ('a' - 'A'));
changed = true;
type = CHAR_NAME;
} else if (c >= 'A' && c <= 'Z') {
type = CHAR_NAME;
} else if (c >= '0' && c <= '9') {
type = CHAR_VALUE;
} else {
if (false) { // TODO 95 Character.isJavaIdentifierPart(c)) {
type = CHAR_NAME;
char u = Character.toUpperCase(c);
if (u != c) {
command[i] = u;
changed = true;
}
}
}
}
types[i] = type;
lastType = type;
}
sqlCommandChars = command;
types[len] = CHAR_END;
characterTypes = types;
if (changed) {
sqlCommand = new String(command);
}
parseIndex = 0;
}
private void checkRunOver(int i, int len, int startLoop) throws SQLException {
if (i >= len) {
parseIndex = startLoop;
throw getSyntaxError();
}
}
private int getSpecialType(String s) throws SQLException {
char c0 = s.charAt(0);
if (s.length() == 1) {
switch (c0) {
case '?':
case '$':
return PARAMETER;
case '@':
return AT;
case '+':
return PLUS;
case '-':
return MINUS;
case '{':
case '}':
case '*':
case '/':
case ';':
case ',':
case ':':
case '[':
case ']':
case '~':
return KEYWORD;
case '(':
return OPEN;
case ')':
return CLOSE;
case '<':
return SMALLER;
case '>':
return BIGGER;
case '=':
return EQUAL;
default:
break;
}
} else if (s.length() == 2) {
switch (c0) {
case ':':
if ("::".equals(s)) {
return KEYWORD;
} else if (":=".equals(s)) {
return KEYWORD;
}
break;
case '>':
if (">=".equals(s)) {
return BIGGER_EQUAL;
}
break;
case '<':
if ("<=".equals(s)) {
return SMALLER_EQUAL;
} else if ("<>".equals(s)) {
return NOT_EQUAL;
}
break;
case '!':
if ("!=".equals(s)) {
return NOT_EQUAL;
} else if ("!~".equals(s)) {
return KEYWORD;
}
break;
case '|':
if ("||".equals(s)) {
return STRING_CONCAT;
}
break;
}
}
throw getSyntaxError();
}
private int getTokenType(String s) throws SQLException {
int len = s.length();
if (len == 0) {
throw getSyntaxError();
}
return getSaveTokenType(s, false); //database.getMode().supportOffsetFetch);
}
/**
* Checks if this string is a SQL keyword.
*
* @param s the token to check
* @param supportOffsetFetch if OFFSET and FETCH are keywords
* @return true if it is a keyword
*/
public static boolean isKeyword(String s, boolean supportOffsetFetch) {
if (s == null || s.length() == 0) {
return false;
}
return getSaveTokenType(s, supportOffsetFetch) != IDENTIFIER;
}
private static int getSaveTokenType(String s, boolean supportOffsetFetch) {
switch (s.charAt(0)) {
case 'C':
if (s.equals("CURRENT_TIMESTAMP")) {
return CURRENT_TIMESTAMP;
} else if (s.equals("CURRENT_TIME")) {
return CURRENT_TIME;
} else if (s.equals("CURRENT_DATE")) {
return CURRENT_DATE;
}
return getKeywordOrIdentifier(s, "CROSS", KEYWORD);
case 'D':
return getKeywordOrIdentifier(s, "DISTINCT", KEYWORD);
case 'E':
if ("EXCEPT".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "EXISTS", KEYWORD);
case 'F':
if ("FROM".equals(s)) {
return KEYWORD;
} else if ("FOR".equals(s)) {
return KEYWORD;
} else if ("FULL".equals(s)) {
return KEYWORD;
} else if (supportOffsetFetch && "FETCH".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "FALSE", FALSE);
case 'G':
return getKeywordOrIdentifier(s, "GROUP", KEYWORD);
case 'H':
return getKeywordOrIdentifier(s, "HAVING", KEYWORD);
case 'I':
if ("INNER".equals(s)) {
return KEYWORD;
} else if ("INTERSECT".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "IS", KEYWORD);
case 'J':
return getKeywordOrIdentifier(s, "JOIN", KEYWORD);
case 'L':
if ("LIMIT".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "LIKE", KEYWORD);
case 'M':
return getKeywordOrIdentifier(s, "MINUS", KEYWORD);
case 'N':
if ("NOT".equals(s)) {
return KEYWORD;
} else if ("NATURAL".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "NULL", NULL);
case 'O':
if ("ON".equals(s)) {
return KEYWORD;
} else if (supportOffsetFetch && "OFFSET".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "ORDER", KEYWORD);
case 'P':
return getKeywordOrIdentifier(s, "PRIMARY", KEYWORD);
case 'R':
return getKeywordOrIdentifier(s, "ROWNUM", ROWNUM);
case 'S':
if (s.equals("SYSTIMESTAMP")) {
return CURRENT_TIMESTAMP;
} else if (s.equals("SYSTIME")) {
return CURRENT_TIME;
} else if (s.equals("SYSDATE")) {
return CURRENT_TIMESTAMP;
}
return getKeywordOrIdentifier(s, "SELECT", KEYWORD);
case 'T':
if ("TODAY".equals(s)) {
return CURRENT_DATE;
}
return getKeywordOrIdentifier(s, "TRUE", TRUE);
case 'U':
if ("UNIQUE".equals(s)) {
return KEYWORD;
}
return getKeywordOrIdentifier(s, "UNION", KEYWORD);
case 'W':
return getKeywordOrIdentifier(s, "WHERE", KEYWORD);
default:
return IDENTIFIER;
}
}
private static int getKeywordOrIdentifier(String s1, String s2, int keywordType) {
if (s1.equals(s2)) {
return keywordType;
}
return IDENTIFIER;
}
private Column parseColumnForTable(String columnName) throws SQLException {
return null;
}
private void parseAutoIncrement(Column column) throws SQLException {
long start = 1, increment = 1;
if (readIf("(")) {
start = readLong();
if (readIf(",")) {
increment = readLong();
}
read(")");
}
// column.setAutoIncrement(true, start, increment);
}
private String readCommentIf() throws SQLException {
if (readIf("COMMENT")) {
readIf("IS");
return readString();
}
return null;
}
private Column parseColumn(String columnName) throws SQLException {
return null;
}
private Prepared parseCreate() throws SQLException {
return null;
}
private boolean addRoleOrRight(int command) throws SQLException {
return false;
}
private Prepared parseGrantRevoke(int operationType) throws SQLException {
return null;
}
private Prepared parserCall() throws SQLException {
// Call command = new Call(session);
// currentPrepared = command;
// command.setValue(readExpression());
// return command;
return null;
}
private Prepared parseCreateRole() throws SQLException {
return null;
}
private Prepared parseCreateSchema() throws SQLException {
return null;
}
private Prepared parseCreateSequence() throws SQLException {
return null;
}
private boolean readIfNoExists() throws SQLException {
if (readIf("IF")) {
read("NOT");
read("EXISTS");
return true;
}
return false;
}
private Prepared parseCreateConstant() throws SQLException {
return null;
}
private Prepared parseCreateAggregate(boolean force) throws SQLException {
// boolean ifNotExists = readIfNoExists();
// CreateAggregate command = new CreateAggregate(session);
// command.setForce(force);
// String name = readUniqueIdentifier();
// if (isKeyword(name, false) || Function.getFunction(database, name) != null || Aggregate.getAggregateType(name) >= 0) {
// throw Message.getSQLException(ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1, name);
// }
// command.setName(name);
// command.setIfNotExists(ifNotExists);
// read("FOR");
// command.setJavaClassMethod(readUniqueIdentifier());
// return command;
return null;
}
private Prepared parseCreateUserDataType() throws SQLException {
return null;
}
private Prepared parseCreateTrigger(boolean force) throws SQLException {
return null;
}
private Prepared parseCreateUser() throws SQLException {
return null;
}
private Prepared parseCreateFunctionAlias(boolean force) throws SQLException {
return null;
}
private Prepared parserWith() throws SQLException {
return null;
}
private Prepared parseCreateView(boolean force) throws SQLException {
return null;
}
private Prepared parseCheckpoint() throws SQLException {
return null;
}
private Prepared parseAlter() throws SQLException {
if (readIf("TABLE")) {
return parseAlterTable();
} else if (readIf("USER")) {
return parseAlterUser();
} else if (readIf("INDEX")) {
return parseAlterIndex();
} else if (readIf("SEQUENCE")) {
return parseAlterSequence();
} else if (readIf("VIEW")) {
return parseAlterView();
}
throw getSyntaxError();
}
private void checkSchema(Schema old) throws SQLException {
if (old != null && getSchema() != old) {
throw Message.getSQLException(ErrorCode.SCHEMA_NAME_MUST_MATCH);
}
}
private Prepared parseAlterIndex() throws SQLException {
return null;
// String indexName = readIdentifierWithSchema();
// Schema old = getSchema();
// AlterIndexRename command = new AlterIndexRename(session);
//
// read("RENAME");
// read("TO");
// String newName = readIdentifierWithSchema(old.getName());
// checkSchema(old);
// command.setNewName(newName);
// return command;
}
private Prepared parseAlterView() throws SQLException {
// AlterView command = new AlterView(session);
// String viewName = readIdentifierWithSchema();
// Table tableView = getSchema().findTableOrView(session, viewName);
// if (!(tableView instanceof TableView)) {
// throw Message.getSQLException(ErrorCode.VIEW_NOT_FOUND_1, viewName);
// }
// TableView view = (TableView) tableView;
// command.setView(view);
// read("RECOMPILE");
// return command;
return null;
}
private Prepared parseAlterSequence() throws SQLException {
return null;
}
private Prepared parseAlterUser() throws SQLException {
// String userName = readUniqueIdentifier();
// if (readIf("SET")) {
// AlterUser command = new AlterUser(session);
// command.setType(AlterUser.SET_PASSWORD);
// command.setUser(database.getUser(userName));
// if (readIf("PASSWORD")) {
// command.setPassword(readExpression());
// } else if (readIf("SALT")) {
// command.setSalt(readExpression());
// read("HASH");
// command.setHash(readExpression());
// } else {
// throw getSyntaxError();
// }
// return command;
// } else if (readIf("RENAME")) {
// read("TO");
// AlterUser command = new AlterUser(session);
// command.setType(AlterUser.RENAME);
// command.setUser(database.getUser(userName));
// String newName = readUniqueIdentifier();
// command.setNewName(newName);
// return command;
// } else if (readIf("ADMIN")) {
// AlterUser command = new AlterUser(session);
// command.setType(AlterUser.ADMIN);
// User user = database.getUser(userName);
// command.setUser(user);
// if (readIf("TRUE")) {
// command.setAdmin(true);
// } else if (readIf("FALSE")) {
// command.setAdmin(false);
// } else {
// throw getSyntaxError();
// }
// return command;
// }
// throw getSyntaxError();
return null;
}
private void readIfEqualOrTo() throws SQLException {
if (!readIf("=")) {
readIf("TO");
}
}
private Prepared parseSet() throws SQLException {
return null;
}
private Prepared parseSetCollation() throws SQLException {
return null;
}
private Prepared parseRunScript() throws SQLException {
return null;
}
private Prepared parseScript() throws SQLException {
return null;
}
private Table readTableOrView() throws SQLException {
return readTableOrView(readIdentifierWithSchema(null));
}
private Table readTableOrView(String tableName) throws SQLException {
// // same algorithm than readSequence
// if (schemaName != null) {
// return getSchema().getTableOrView(session, tableName);
// }
Table table = database.getMainSchema(
//session.getCurrentSchemaName()
).findTableOrView(tableName);
if (table != null) {
return table;
}
// throw new RuntimeException("Unable to find table " + tableName);
// String[] schemaNames = session.getSchemaSearchPath();
// for (int i = 0; schemaNames != null && i < schemaNames.length; i++) {
// Schema s = database.getSchema(schemaNames[i]);
// table = s.findTableOrView(session, tableName);
// if (table != null) {
// return table;
// }
// }
throw new SQLException("Unable to find table " + tableName);
}
private Sequence findSequence(String schemaName, String sequenceName) throws SQLException {
// Sequence sequence = database.getSchema(schemaName).findSequence(sequenceName);
// if (sequence != null) {
// return sequence;
// }
// String[] schemaNames = session.getSchemaSearchPath();
// for (int i = 0; schemaNames != null && i < schemaNames.length; i++) {
// Schema s = database.getSchema(schemaNames[i]);
// sequence = s.findSequence(sequenceName);
// if (sequence != null) {
// return sequence;
// }
// }
return null;
}
private Sequence readSequence() throws SQLException {
// // same algorithm than readTableOrView
// String sequenceName = readIdentifierWithSchema(null);
// if (schemaName != null) {
// return getSchema().getSequence(sequenceName);
// }
// Sequence sequence = findSequence(session.getCurrentSchemaName(), sequenceName);
// if (sequence != null) {
// return sequence;
// }
throw Message.getSQLException(ErrorCode.SEQUENCE_NOT_FOUND_1, "sequenceName");
}
private Prepared parseAlterTable() throws SQLException {
Table table = readTableOrView();
if (readIf("ADD")) {
Prepared command = parseAlterTableAddConstraintIf(table.getName(), table.getSchema());
if (command != null) {
return command;
}
return parseAlterTableAddColumn(table);
} else if (readIf("SET")) {
return null;
} else if (readIf("RENAME")) {
read("TO");
//String newName = readIdentifierWithSchema(table.getSchema().getName());
//checkSchema(table.getSchema());
return null;
} else if (readIf("DROP")) {
if (readIf("CONSTRAINT")) {
return null;
} else if (readIf("PRIMARY")) {
read("KEY");
return null;
} else {
readIf("COLUMN");
return null;
}
} else if (readIf("ALTER")) {
readIf("COLUMN");
String columnName = readColumnIdentifier();
Column column = null; //table.getColumn(columnName);
if (readIf("RENAME")) {
read("TO");
return null;
} else if (readIf("SET")) {
if (readIf("DATA")) {
// Derby compatibility
read("TYPE");
Column newColumn = parseColumnForTable(columnName);
return null;
}
return null;
} else if (readIf("RESTART")) {
readIf("WITH");
Expression start = readExpression();
return null;
} else if (readIf("SELECTIVITY")) {
return null;
} else {
Column newColumn = parseColumnForTable(columnName);
return null;
}
}
throw getSyntaxError();
}
private Prepared parseAlterTableAddColumn(Table table) throws SQLException {
return null;
}
private int parseAction() throws SQLException {
return 0;
}
private Prepared parseAlterTableAddConstraintIf(String tableName, Schema schema) throws SQLException {
String constraintName = null, comment = null;
boolean ifNotExists = false;
if (readIf("CONSTRAINT")) {
ifNotExists = readIfNoExists();
constraintName = readIdentifierWithSchema(schema.getName());
checkSchema(schema);
comment = readCommentIf();
}
if (readIf("PRIMARY")) {
read("KEY");
return null;
} else if (false && (readIf("INDEX") || readIf("KEY"))) {
// MySQL
return null;
}
Prepared command;
if (readIf("CHECK")) {
command = null; //new AlterTableAddConstraint(session, schema, ifNotExists);
//command.setType(AlterTableAddConstraint.CHECK);
//command.setCheckExpression(readExpression());
} else if (readIf("UNIQUE")) {
readIf("KEY");
readIf("INDEX");
command = null; //new AlterTableAddConstraint(session, schema, ifNotExists);
//command.setType(AlterTableAddConstraint.UNIQUE);
if (!readIf("(")) {
constraintName = readUniqueIdentifier();
read("(");
}
//command.setIndexColumns(parseIndexColumnList());
if (readIf("INDEX")) {
String indexName = readIdentifierWithSchema();
}
} else if (readIf("FOREIGN")) {
command = null;
read("KEY");
read("(");
//command.setIndexColumns(parseIndexColumnList());
if (readIf("INDEX")) {
String indexName = readIdentifierWithSchema();
}
read("REFERENCES");
parseReferences(command, schema, tableName);
} else {
if (constraintName != null) {
throw getSyntaxError();
}
return null;
}
if (readIf("NOCHECK")) {
//command.setCheckExisting(false);
} else {
readIf("CHECK");
//command.setCheckExisting(true);
}
//command.setTableName(tableName);
//command.setConstraintName(constraintName);
//command.setComment(comment);
return command;
}
private void parseReferences(Prepared command, Schema schema, String tableName) throws SQLException {
// if (readIf("(")) {
// command.setRefTableName(schema, tableName);
// command.setRefIndexColumns(parseIndexColumnList());
// } else {
// String refTableName = readIdentifierWithSchema(schema.getName());
// command.setRefTableName(getSchema(), refTableName);
// if (readIf("(")) {
// command.setRefIndexColumns(parseIndexColumnList());
// }
// }
// if (readIf("INDEX")) {
// String indexName = readIdentifierWithSchema();
//
// }
// while (readIf("ON")) {
// if (readIf("DELETE")) {
// command.setDeleteAction(parseAction());
// } else {
// read("UPDATE");
// command.setUpdateAction(parseAction());
// }
// }
// if (readIf("NOT")) {
// read("DEFERRABLE");
// } else {
// readIf("DEFERRABLE");
// }
}
private Prepared parseCreateLinkedTable(boolean temp, boolean globalTemp, boolean force) throws SQLException {
return null;
}
private Prepared parseCreateTable(boolean temp, boolean globalTemp, boolean persistIndexes) throws SQLException {
return null;
}
private String getCompareType(int tokenType) {
switch (tokenType) {
case EQUAL:
return Operator.EQUAL;
case BIGGER_EQUAL:
return Operator.BIGGER_EQUAL;
case BIGGER:
return Operator.BIGGER;
case SMALLER:
return Operator.SMALLER;
case SMALLER_EQUAL:
return Operator.SMALLER_EQUAL;
case NOT_EQUAL:
return Operator.NOT_EQUAL;
default:
return null;
}
}
public void setRightsChecked(boolean rightsChecked) {
this.rightsChecked = rightsChecked;
}
/**
* Parse a SQL code snippet that represents an expression.
*
* @param sql the code snippet
* @return the expression object
* @throws SQLException if the code snippet could not be parsed
*/
public Expression parseExpression(String sql) throws SQLException {
parameters = ObjectArray.newInstance();
initialize(sql);
read();
return readExpression();
}
}