提交 94d97acd authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add token types for all keywords and use them instead of strings

上级 81bb6b2e
...@@ -8,12 +8,44 @@ ...@@ -8,12 +8,44 @@
*/ */
package org.h2.command; package org.h2.command;
import static org.h2.util.ParserUtil.ALL;
import static org.h2.util.ParserUtil.CHECK;
import static org.h2.util.ParserUtil.CONSTRAINT;
import static org.h2.util.ParserUtil.CROSS;
import static org.h2.util.ParserUtil.DISTINCT;
import static org.h2.util.ParserUtil.EXCEPT;
import static org.h2.util.ParserUtil.EXISTS;
import static org.h2.util.ParserUtil.FALSE; import static org.h2.util.ParserUtil.FALSE;
import static org.h2.util.ParserUtil.FETCH;
import static org.h2.util.ParserUtil.FOR;
import static org.h2.util.ParserUtil.FOREIGN;
import static org.h2.util.ParserUtil.FROM;
import static org.h2.util.ParserUtil.FULL;
import static org.h2.util.ParserUtil.GROUP;
import static org.h2.util.ParserUtil.HAVING;
import static org.h2.util.ParserUtil.IDENTIFIER; import static org.h2.util.ParserUtil.IDENTIFIER;
import static org.h2.util.ParserUtil.INNER;
import static org.h2.util.ParserUtil.INTERSECT;
import static org.h2.util.ParserUtil.IS;
import static org.h2.util.ParserUtil.JOIN;
import static org.h2.util.ParserUtil.KEYWORD; import static org.h2.util.ParserUtil.KEYWORD;
import static org.h2.util.ParserUtil.LIKE;
import static org.h2.util.ParserUtil.LIMIT;
import static org.h2.util.ParserUtil.MINUS;
import static org.h2.util.ParserUtil.NATURAL;
import static org.h2.util.ParserUtil.NOT;
import static org.h2.util.ParserUtil.NULL; import static org.h2.util.ParserUtil.NULL;
import static org.h2.util.ParserUtil.OFFSET;
import static org.h2.util.ParserUtil.ON;
import static org.h2.util.ParserUtil.ORDER;
import static org.h2.util.ParserUtil.PRIMARY;
import static org.h2.util.ParserUtil.ROWNUM; import static org.h2.util.ParserUtil.ROWNUM;
import static org.h2.util.ParserUtil.SELECT;
import static org.h2.util.ParserUtil.TRUE; import static org.h2.util.ParserUtil.TRUE;
import static org.h2.util.ParserUtil.UNION;
import static org.h2.util.ParserUtil.UNIQUE;
import static org.h2.util.ParserUtil.WHERE;
import static org.h2.util.ParserUtil.WITH;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
...@@ -197,13 +229,206 @@ public class Parser { ...@@ -197,13 +229,206 @@ public class Parser {
CHAR_DOLLAR_QUOTED_STRING = 9; CHAR_DOLLAR_QUOTED_STRING = 9;
// this are token types, see also types in ParserUtil // this are token types, see also types in ParserUtil
private static final int PARAMETER = 10, END = 11, VALUE = 12;
private static final int EQUAL = 13, BIGGER_EQUAL = 14, BIGGER = 15; /**
private static final int SMALLER = 16, SMALLER_EQUAL = 17, NOT_EQUAL = 18; * Token with parameter.
private static final int AT = 19; */
private static final int MINUS = 20, PLUS = 21, STRING_CONCAT = 22; private static final int PARAMETER = WITH + 1;
private static final int OPEN = 23, CLOSE = 24;
private static final int SPATIAL_INTERSECTS = 25; /**
* End of input.
*/
private static final int END = PARAMETER + 1;
/**
* Token with value.
*/
private static final int VALUE = END + 1;
/**
* The token "=".
*/
private static final int EQUAL = VALUE + 1;
/**
* The token ">=".
*/
private static final int BIGGER_EQUAL = EQUAL + 1;
/**
* The token ">".
*/
private static final int BIGGER = BIGGER_EQUAL + 1;
/**
* The token "<".
*/
private static final int SMALLER = BIGGER + 1;
/**
* The token "<=".
*/
private static final int SMALLER_EQUAL = SMALLER + 1;
/**
* The token "<>" or "!=".
*/
private static final int NOT_EQUAL = SMALLER_EQUAL + 1;
/**
* The token "@".
*/
private static final int AT = NOT_EQUAL + 1;
/**
* The token "-".
*/
private static final int MINUS_SIGN = AT + 1;
/**
* The token "+".
*/
private static final int PLUS_SIGN = MINUS_SIGN + 1;
/**
* The token "||".
*/
private static final int STRING_CONCAT = PLUS_SIGN + 1;
/**
* The token "(".
*/
private static final int OPEN_PAREN = STRING_CONCAT + 1;
/**
* The token ")".
*/
private static final int CLOSE_PAREN = OPEN_PAREN + 1;
/**
* The token "&&".
*/
private static final int SPATIAL_INTERSECTS = CLOSE_PAREN + 1;
private static final String[] TOKENS = {
// Unused
null,
// KEYWORD
null,
// IDENTIFIER
null,
// ALL
"ALL",
// CHECK
"CHECK",
// CONSTRAINT
"CONSTRAINT",
// CROSS
"CROSS",
// CURRENT_DATE
"CURRENT_DATE",
// CURRENT_TIME
"CURRENT_TIME",
// CURRENT_TIMESTAMP
"CURRENT_TIMESTAMP",
// DISTINCT
"DISTINCT",
// EXCEPT
"EXCEPT",
// EXISTS
"EXISTS",
// FALSE
"FALSE",
// FETCH
"FETCH",
// FOR
"FOR",
// FOREIGN
"FOREIGN",
// FROM
"FROM",
// FULL
"FULL",
// GROUP
"GROUP",
// HAVING
"HAVING",
// INNER
"INNER",
// INTERSECT
"INTERSECT",
// IS
"IS",
// JOIN
"JOIN",
// LIKE
"LIKE",
// LIMIT
"LIMIT",
// MINUS
"MINUS",
// NATURAL
"NATURAL",
// NOT
"NOT",
// NULL
"NULL",
// OFFSET
"OFFSET",
// ON
"ON",
// ORDER
"ORDER",
// PRIMARY
"PRIMARY",
// ROWNUM
"ROWNUM",
// SELECT
"SELECT",
// TRUE
"TRUE",
// UNION
"UNION",
// UNIQUE
"UNIQUE",
// WHERE
"WHERE",
// WITH
"WITH",
// PARAMETER
"?",
// END
null,
// VALUE
null,
// EQUAL
"=",
// BIGGER_EQUAL
">=",
// BIGGER
">",
// SMALLER
"<",
// SMALLER_EQUAL
"<=",
// NOT_EQUAL
"<>",
// AT
"@",
// MINUS_SIGN
"-",
// PLUS_SIGN
"+",
// STRING_CONCAT
"||",
// OPEN_PAREN
"(",
// CLOSE_PAREN
")",
// SPATIAL_INTERSECTS
"&&",
// End
};
private static final Comparator<TableFilter> TABLE_FILTER_COMPARATOR = private static final Comparator<TableFilter> TABLE_FILTER_COMPARATOR =
new Comparator<TableFilter>() { new Comparator<TableFilter>() {
...@@ -354,7 +579,7 @@ public class Parser { ...@@ -354,7 +579,7 @@ public class Parser {
readTerm(); readTerm();
// this is an 'out' parameter - set a dummy value // this is an 'out' parameter - set a dummy value
parameters.get(0).setValue(ValueNull.INSTANCE); parameters.get(0).setValue(ValueNull.INSTANCE);
read("="); read(EQUAL);
read("CALL"); read("CALL");
c = parseCall(); c = parseCall();
break; break;
...@@ -414,7 +639,7 @@ public class Parser { ...@@ -414,7 +639,7 @@ public class Parser {
break; break;
case 'f': case 'f':
case 'F': case 'F':
if (isToken("FROM")) { if (isToken(FROM)) {
c = parseSelect(); c = parseSelect();
} }
break; break;
...@@ -464,7 +689,7 @@ public class Parser { ...@@ -464,7 +689,7 @@ public class Parser {
break; break;
case 's': case 's':
case 'S': case 'S':
if (isToken("SELECT")) { if (isToken(SELECT)) {
c = parseSelect(); c = parseSelect();
} else if (readIf("SET")) { } else if (readIf("SET")) {
c = parseSet(); c = parseSet();
...@@ -500,7 +725,7 @@ public class Parser { ...@@ -500,7 +725,7 @@ public class Parser {
break; break;
case 'w': case 'w':
case 'W': case 'W':
if (readIf("WITH")) { if (readIf(WITH)) {
c = parseWithStatementOrQuery(); c = parseWithStatementOrQuery();
} }
break; break;
...@@ -646,7 +871,7 @@ public class Parser { ...@@ -646,7 +871,7 @@ public class Parser {
return command; return command;
} }
String procedureName = readAliasIdentifier(); String procedureName = readAliasIdentifier();
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
ArrayList<Column> list = Utils.newSmallArrayList(); ArrayList<Column> list = Utils.newSmallArrayList();
for (int i = 0;; i++) { for (int i = 0;; i++) {
Column column = parseColumnForTable("C" + i, true, false); Column column = parseColumnForTable("C" + i, true, false);
...@@ -782,13 +1007,13 @@ public class Parser { ...@@ -782,13 +1007,13 @@ public class Parser {
private void parseUpdateSetClause(Update command, TableFilter filter, int start) { private void parseUpdateSetClause(Update command, TableFilter filter, int start) {
read("SET"); read("SET");
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
ArrayList<Column> columns = Utils.newSmallArrayList(); ArrayList<Column> columns = Utils.newSmallArrayList();
do { do {
Column column = readTableColumn(filter); Column column = readTableColumn(filter);
columns.add(column); columns.add(column);
} while (readIfMore(true)); } while (readIfMore(true));
read("="); read(EQUAL);
Expression expression = readExpression(); Expression expression = readExpression();
if (columns.size() == 1) { if (columns.size() == 1) {
// the expression is parsed as a simple value // the expression is parsed as a simple value
...@@ -806,21 +1031,21 @@ public class Parser { ...@@ -806,21 +1031,21 @@ public class Parser {
} else { } else {
do { do {
Column column = readTableColumn(filter); Column column = readTableColumn(filter);
read("="); read(EQUAL);
command.setAssignment(column, readExpressionOrDefault()); command.setAssignment(column, readExpressionOrDefault());
} while (readIf(",")); } while (readIf(","));
} }
if (readIf("WHERE")) { if (readIf(WHERE)) {
Expression condition = readExpression(); Expression condition = readExpression();
command.setCondition(condition); command.setCondition(condition);
} }
if (readIf("ORDER")) { if (readIf(ORDER)) {
// for MySQL compatibility // for MySQL compatibility
// (this syntax is supported, but ignored) // (this syntax is supported, but ignored)
read("BY"); read("BY");
parseSimpleOrderList(); parseSimpleOrderList();
} }
if (readIf("LIMIT")) { if (readIf(LIMIT)) {
Expression limit = readTerm().optimize(session); Expression limit = readTerm().optimize(session);
command.setLimit(limit); command.setLimit(limit);
} }
...@@ -851,9 +1076,9 @@ public class Parser { ...@@ -851,9 +1076,9 @@ public class Parser {
} }
currentPrepared = command; currentPrepared = command;
int start = lastParseIndex; int start = lastParseIndex;
if (!readIf("FROM") && database.getMode().getEnum() == ModeEnum.MySQL) { if (!readIf(FROM) && database.getMode().getEnum() == ModeEnum.MySQL) {
readIdentifierWithSchema(); readIdentifierWithSchema();
read("FROM"); read(FROM);
} }
TableFilter filter = readSimpleTableFilter(0, null); TableFilter filter = readSimpleTableFilter(0, null);
command.setTableFilter(filter); command.setTableFilter(filter);
...@@ -862,11 +1087,11 @@ public class Parser { ...@@ -862,11 +1087,11 @@ public class Parser {
} }
private void parseDeleteGivenTable(Delete command, Expression limit, int start) { private void parseDeleteGivenTable(Delete command, Expression limit, int start) {
if (readIf("WHERE")) { if (readIf(WHERE)) {
Expression condition = readExpression(); Expression condition = readExpression();
command.setCondition(condition); command.setCondition(condition);
} }
if (readIf("LIMIT") && limit == null) { if (readIf(LIMIT) && limit == null) {
limit = readTerm().optimize(session); limit = readTerm().optimize(session);
} }
command.setLimit(limit); command.setLimit(limit);
...@@ -914,7 +1139,7 @@ public class Parser { ...@@ -914,7 +1139,7 @@ public class Parser {
private Column[] parseColumnList(Table table) { private Column[] parseColumnList(Table table) {
ArrayList<Column> columns = Utils.newSmallArrayList(); ArrayList<Column> columns = Utils.newSmallArrayList();
HashSet<Column> set = new HashSet<>(); HashSet<Column> set = new HashSet<>();
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
Column column = parseColumn(table); Column column = parseColumn(table);
if (!set.add(column)) { if (!set.add(column)) {
...@@ -944,9 +1169,9 @@ public class Parser { ...@@ -944,9 +1169,9 @@ public class Parser {
*/ */
private boolean readIfMore(boolean strict) { private boolean readIfMore(boolean strict) {
if (readIf(",")) { if (readIf(",")) {
return strict || !readIf(")"); return strict || !readIf(CLOSE_PAREN);
} }
read(")"); read(CLOSE_PAREN);
return false; return false;
} }
...@@ -998,7 +1223,7 @@ public class Parser { ...@@ -998,7 +1223,7 @@ public class Parser {
} else if (readIf("TABLES")) { } else if (readIf("TABLES")) {
// for MySQL compatibility // for MySQL compatibility
String schema = Constants.SCHEMA_MAIN; String schema = Constants.SCHEMA_MAIN;
if (readIf("FROM")) { if (readIf(FROM)) {
schema = readUniqueIdentifier(); schema = readUniqueIdentifier();
} }
buff.append("TABLE_NAME, TABLE_SCHEMA FROM " buff.append("TABLE_NAME, TABLE_SCHEMA FROM "
...@@ -1007,11 +1232,11 @@ public class Parser { ...@@ -1007,11 +1232,11 @@ public class Parser {
paramValues.add(ValueString.get(schema)); paramValues.add(ValueString.get(schema));
} else if (readIf("COLUMNS")) { } else if (readIf("COLUMNS")) {
// for MySQL compatibility // for MySQL compatibility
read("FROM"); read(FROM);
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
String schemaName = getSchema().getName(); String schemaName = getSchema().getName();
paramValues.add(ValueString.get(tableName)); paramValues.add(ValueString.get(tableName));
if (readIf("FROM")) { if (readIf(FROM)) {
schemaName = readUniqueIdentifier(); schemaName = readUniqueIdentifier();
} }
buff.append("C.COLUMN_NAME FIELD, " buff.append("C.COLUMN_NAME FIELD, "
...@@ -1059,11 +1284,11 @@ public class Parser { ...@@ -1059,11 +1284,11 @@ public class Parser {
private boolean isSelect() { private boolean isSelect() {
int start = lastParseIndex; int start = lastParseIndex;
while (readIf("(")) { while (readIf(OPEN_PAREN)) {
// need to read ahead, it could be a nested union: // need to read ahead, it could be a nested union:
// ((select 1) union (select 1)) // ((select 1) union (select 1))
} }
boolean select = isToken("SELECT") || isToken("FROM") || isToken("WITH"); boolean select = isToken(SELECT) || isToken(FROM) || isToken(WITH);
parseIndex = start; parseIndex = start;
read(); read();
return select; return select;
...@@ -1083,23 +1308,23 @@ public class Parser { ...@@ -1083,23 +1308,23 @@ public class Parser {
if (readIf("USING")) { if (readIf("USING")) {
return parseMergeUsing(command, start); return parseMergeUsing(command, start);
} }
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
if (isSelect()) { if (isSelect()) {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
read(")"); read(CLOSE_PAREN);
return command; return command;
} }
Column[] columns = parseColumnList(table); Column[] columns = parseColumnList(table);
command.setColumns(columns); command.setColumns(columns);
} }
if (readIf("KEY")) { if (readIf("KEY")) {
read("("); read(OPEN_PAREN);
Column[] keys = parseColumnList(table); Column[] keys = parseColumnList(table);
command.setKeys(keys); command.setKeys(keys);
} }
if (readIf("VALUES")) { if (readIf("VALUES")) {
do { do {
read("("); read(OPEN_PAREN);
command.addRow(parseValuesForInsert()); command.addRow(parseValuesForInsert());
} while (readIf(",")); } while (readIf(","));
} else { } else {
...@@ -1112,11 +1337,11 @@ public class Parser { ...@@ -1112,11 +1337,11 @@ public class Parser {
MergeUsing command = new MergeUsing(oldCommand); MergeUsing command = new MergeUsing(oldCommand);
currentPrepared = command; currentPrepared = command;
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
/* a select query is supplied */ /* a select query is supplied */
if (isSelect()) { if (isSelect()) {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
read(")"); read(CLOSE_PAREN);
} }
String queryAlias = readFromAlias(null, Collections.singletonList("ON")); String queryAlias = readFromAlias(null, Collections.singletonList("ON"));
if (queryAlias == null) { if (queryAlias == null) {
...@@ -1153,7 +1378,7 @@ public class Parser { ...@@ -1153,7 +1378,7 @@ public class Parser {
preparedQuery.init(); preparedQuery.init();
command.setQuery(preparedQuery); command.setQuery(preparedQuery);
} }
read("ON"); read(ON);
Expression condition = readExpression(); Expression condition = readExpression();
command.setOnCondition(condition); command.setOnCondition(condition);
...@@ -1215,7 +1440,7 @@ public class Parser { ...@@ -1215,7 +1440,7 @@ public class Parser {
} }
private void parseWhenNotMatched(MergeUsing command) { private void parseWhenNotMatched(MergeUsing command) {
read("NOT"); read(NOT);
read("MATCHED"); read("MATCHED");
read("THEN"); read("THEN");
if (readIf("INSERT")) { if (readIf("INSERT")) {
...@@ -1254,7 +1479,7 @@ public class Parser { ...@@ -1254,7 +1479,7 @@ public class Parser {
return returnedCommand; return returnedCommand;
} }
if (database.getMode().onDuplicateKeyUpdate) { if (database.getMode().onDuplicateKeyUpdate) {
if (readIf("ON")) { if (readIf(ON)) {
read("DUPLICATE"); read("DUPLICATE");
read("KEY"); read("KEY");
read("UPDATE"); read("UPDATE");
...@@ -1277,7 +1502,7 @@ public class Parser { ...@@ -1277,7 +1502,7 @@ public class Parser {
} }
} }
Column column = table.getColumn(columnName); Column column = table.getColumn(columnName);
read("="); read(EQUAL);
command.addAssignmentForDuplicate(column, readExpressionOrDefault()); command.addAssignmentForDuplicate(column, readExpressionOrDefault());
} while (readIf(",")); } while (readIf(","));
} }
...@@ -1290,10 +1515,10 @@ public class Parser { ...@@ -1290,10 +1515,10 @@ public class Parser {
private Insert parseInsertGivenTable(Insert command, Table table) { private Insert parseInsertGivenTable(Insert command, Table table) {
Column[] columns = null; Column[] columns = null;
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
if (isSelect()) { if (isSelect()) {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
read(")"); read(CLOSE_PAREN);
return command; return command;
} }
columns = parseColumnList(table); columns = parseColumnList(table);
...@@ -1310,11 +1535,11 @@ public class Parser { ...@@ -1310,11 +1535,11 @@ public class Parser {
Expression[] expr = {}; Expression[] expr = {};
command.addRow(expr); command.addRow(expr);
} else if (readIf("VALUES")) { } else if (readIf("VALUES")) {
read("("); read(OPEN_PAREN);
do { do {
command.addRow(parseValuesForInsert()); command.addRow(parseValuesForInsert());
// the following condition will allow (..),; and (..); // the following condition will allow (..),; and (..);
} while (readIf(",") && readIf("(")); } while (readIf(",") && readIf(OPEN_PAREN));
} else if (readIf("SET")) { } else if (readIf("SET")) {
if (columns != null) { if (columns != null) {
throw getSyntaxError(); throw getSyntaxError();
...@@ -1323,7 +1548,7 @@ public class Parser { ...@@ -1323,7 +1548,7 @@ public class Parser {
ArrayList<Expression> values = Utils.newSmallArrayList(); ArrayList<Expression> values = Utils.newSmallArrayList();
do { do {
columnList.add(parseColumn(table)); columnList.add(parseColumn(table));
read("="); read(EQUAL);
values.add(readExpressionOrDefault()); values.add(readExpressionOrDefault());
} while (readIf(",")); } while (readIf(","));
command.setColumns(columnList.toArray(new Column[0])); command.setColumns(columnList.toArray(new Column[0]));
...@@ -1343,10 +1568,10 @@ public class Parser { ...@@ -1343,10 +1568,10 @@ public class Parser {
read("INTO"); read("INTO");
Table table = readTableOrView(); Table table = readTableOrView();
command.setTable(table); command.setTable(table);
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
if (isSelect()) { if (isSelect()) {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
read(")"); read(CLOSE_PAREN);
return command; return command;
} }
Column[] columns = parseColumnList(table); Column[] columns = parseColumnList(table);
...@@ -1354,7 +1579,7 @@ public class Parser { ...@@ -1354,7 +1579,7 @@ public class Parser {
} }
if (readIf("VALUES")) { if (readIf("VALUES")) {
do { do {
read("("); read(OPEN_PAREN);
command.addRow(parseValuesForInsert()); command.addRow(parseValuesForInsert());
} while (readIf(",")); } while (readIf(","));
} else { } else {
...@@ -1365,7 +1590,7 @@ public class Parser { ...@@ -1365,7 +1590,7 @@ public class Parser {
private Expression[] parseValuesForInsert() { private Expression[] parseValuesForInsert() {
ArrayList<Expression> values = Utils.newSmallArrayList(); ArrayList<Expression> values = Utils.newSmallArrayList();
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
if (readIf("DEFAULT")) { if (readIf("DEFAULT")) {
values.add(null); values.add(null);
...@@ -1380,10 +1605,10 @@ public class Parser { ...@@ -1380,10 +1605,10 @@ public class Parser {
private TableFilter readTableFilter() { private TableFilter readTableFilter() {
Table table; Table table;
String alias = null; String alias = null;
label: if (readIf("(")) { label: if (readIf(OPEN_PAREN)) {
if (isSelect()) { if (isSelect()) {
Query query = parseSelectUnion(); Query query = parseSelectUnion();
read(")"); read(CLOSE_PAREN);
query.setParameterList(new ArrayList<>(parameters)); query.setParameterList(new ArrayList<>(parameters));
query.init(); query.init();
Session s; Session s;
...@@ -1399,7 +1624,7 @@ public class Parser { ...@@ -1399,7 +1624,7 @@ public class Parser {
TableFilter top; TableFilter top;
top = readTableFilter(); top = readTableFilter();
top = readJoin(top); top = readJoin(top);
read(")"); read(CLOSE_PAREN);
alias = readFromAlias(null); alias = readFromAlias(null);
if (alias != null) { if (alias != null) {
top.setAlias(alias); top.setAlias(alias);
...@@ -1427,12 +1652,12 @@ public class Parser { ...@@ -1427,12 +1652,12 @@ public class Parser {
throw DbException.get(ErrorCode.SCHEMA_NOT_FOUND_1, schemaName); throw DbException.get(ErrorCode.SCHEMA_NOT_FOUND_1, schemaName);
} }
} }
boolean foundLeftBracket = readIf("("); boolean foundLeftBracket = readIf(OPEN_PAREN);
if (foundLeftBracket && readIf("INDEX")) { if (foundLeftBracket && readIf("INDEX")) {
// Sybase compatibility with // Sybase compatibility with
// "select * from test (index table1_index)" // "select * from test (index table1_index)"
readIdentifierWithSchema(null); readIdentifierWithSchema(null);
read(")"); read(CLOSE_PAREN);
foundLeftBracket = false; foundLeftBracket = false;
} }
if (foundLeftBracket) { if (foundLeftBracket) {
...@@ -1444,11 +1669,11 @@ public class Parser { ...@@ -1444,11 +1669,11 @@ public class Parser {
Expression max = readExpression(); Expression max = readExpression();
if (readIf(",")) { if (readIf(",")) {
Expression step = readExpression(); Expression step = readExpression();
read(")"); read(CLOSE_PAREN);
table = new RangeTable(mainSchema, min, max, step, table = new RangeTable(mainSchema, min, max, step,
false); false);
} else { } else {
read(")"); read(CLOSE_PAREN);
table = new RangeTable(mainSchema, min, max, false); table = new RangeTable(mainSchema, min, max, false);
} }
} else { } else {
...@@ -1503,9 +1728,9 @@ public class Parser { ...@@ -1503,9 +1728,9 @@ public class Parser {
if (table == null) { if (table == null) {
throw getSyntaxError(); throw getSyntaxError();
} }
read("("); read(OPEN_PAREN);
LinkedHashSet<String> indexNames = new LinkedHashSet<>(); LinkedHashSet<String> indexNames = new LinkedHashSet<>();
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
String indexName = readIdentifierWithSchema(); String indexName = readIdentifierWithSchema();
Index index = table.getIndex(indexName); Index index = table.getIndex(indexName);
...@@ -1532,7 +1757,7 @@ public class Parser { ...@@ -1532,7 +1757,7 @@ public class Parser {
} }
private ArrayList<String> readDerivedColumnNames() { private ArrayList<String> readDerivedColumnNames() {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
ArrayList<String> derivedColumnNames = new ArrayList<>(); ArrayList<String> derivedColumnNames = new ArrayList<>();
do { do {
derivedColumnNames.add(readAliasIdentifier()); derivedColumnNames.add(readAliasIdentifier());
...@@ -1563,7 +1788,7 @@ public class Parser { ...@@ -1563,7 +1788,7 @@ public class Parser {
private boolean readIfExists(boolean ifExists) { private boolean readIfExists(boolean ifExists) {
if (readIf("IF")) { if (readIf("IF")) {
read("EXISTS"); read(EXISTS);
ifExists = true; ifExists = true;
} }
return ifExists; return ifExists;
...@@ -1571,7 +1796,7 @@ public class Parser { ...@@ -1571,7 +1796,7 @@ public class Parser {
private Prepared parseComment() { private Prepared parseComment() {
int type = 0; int type = 0;
read("ON"); read(ON);
boolean column = false; boolean column = false;
if (readIf("TABLE") || readIf("VIEW")) { if (readIf("TABLE") || readIf("VIEW")) {
type = DbObject.TABLE_OR_VIEW; type = DbObject.TABLE_OR_VIEW;
...@@ -1580,7 +1805,7 @@ public class Parser { ...@@ -1580,7 +1805,7 @@ public class Parser {
type = DbObject.TABLE_OR_VIEW; type = DbObject.TABLE_OR_VIEW;
} else if (readIf("CONSTANT")) { } else if (readIf("CONSTANT")) {
type = DbObject.CONSTANT; type = DbObject.CONSTANT;
} else if (readIf("CONSTRAINT")) { } else if (readIf(CONSTRAINT)) {
type = DbObject.CONSTRAINT; type = DbObject.CONSTRAINT;
} else if (readIf("ALIAS")) { } else if (readIf("ALIAS")) {
type = DbObject.FUNCTION_ALIAS; type = DbObject.FUNCTION_ALIAS;
...@@ -1634,7 +1859,7 @@ public class Parser { ...@@ -1634,7 +1859,7 @@ public class Parser {
command.setSchemaName(schemaName); command.setSchemaName(schemaName);
command.setObjectName(objectName); command.setObjectName(objectName);
command.setObjectType(type); command.setObjectType(type);
read("IS"); read(IS);
command.setCommentExpression(readExpression()); command.setCommentExpression(readExpression());
return command; return command;
} }
...@@ -1670,7 +1895,7 @@ public class Parser { ...@@ -1670,7 +1895,7 @@ public class Parser {
ifExists = readIfExists(ifExists); ifExists = readIfExists(ifExists);
command.setIfExists(ifExists); command.setIfExists(ifExists);
//Support for MySQL: DROP INDEX index_name ON tbl_name //Support for MySQL: DROP INDEX index_name ON tbl_name
if (readIf("ON")) { if (readIf(ON)) {
readIdentifierWithSchema(); readIdentifierWithSchema();
} }
return command; return command;
...@@ -1745,7 +1970,7 @@ public class Parser { ...@@ -1745,7 +1970,7 @@ public class Parser {
command.setDropAction(dropAction); command.setDropAction(dropAction);
} }
return command; return command;
} else if (readIf("ALL")) { } else if (readIf(ALL)) {
read("OBJECTS"); read("OBJECTS");
DropDatabase command = new DropDatabase(session); DropDatabase command = new DropDatabase(session);
command.setDropAllObjects(true); command.setDropAllObjects(true);
...@@ -1798,51 +2023,51 @@ public class Parser { ...@@ -1798,51 +2023,51 @@ public class Parser {
TableFilter join; TableFilter join;
if (readIf("RIGHT")) { if (readIf("RIGHT")) {
readIf("OUTER"); readIf("OUTER");
read("JOIN"); read(JOIN);
// the right hand side is the 'inner' table usually // the right hand side is the 'inner' table usually
join = readTableFilter(); join = readTableFilter();
join = readJoin(join); join = readJoin(join);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf(ON)) {
on = readExpression(); on = readExpression();
} }
addJoin(join, top, true, on); addJoin(join, top, true, on);
top = join; top = join;
} else if (readIf("LEFT")) { } else if (readIf("LEFT")) {
readIf("OUTER"); readIf("OUTER");
read("JOIN"); read(JOIN);
join = readTableFilter(); join = readTableFilter();
join = readJoin(join); join = readJoin(join);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf(ON)) {
on = readExpression(); on = readExpression();
} }
addJoin(top, join, true, on); addJoin(top, join, true, on);
} else if (readIf("FULL")) { } else if (readIf(FULL)) {
throw getSyntaxError(); throw getSyntaxError();
} else if (readIf("INNER")) { } else if (readIf(INNER)) {
read("JOIN"); read(JOIN);
join = readTableFilter(); join = readTableFilter();
top = readJoin(top); top = readJoin(top);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf(ON)) {
on = readExpression(); on = readExpression();
} }
addJoin(top, join, false, on); addJoin(top, join, false, on);
} else if (readIf("JOIN")) { } else if (readIf(JOIN)) {
join = readTableFilter(); join = readTableFilter();
top = readJoin(top); top = readJoin(top);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf(ON)) {
on = readExpression(); on = readExpression();
} }
addJoin(top, join, false, on); addJoin(top, join, false, on);
} else if (readIf("CROSS")) { } else if (readIf(CROSS)) {
read("JOIN"); read(JOIN);
join = readTableFilter(); join = readTableFilter();
addJoin(top, join, false, null); addJoin(top, join, false, null);
} else if (readIf("NATURAL")) { } else if (readIf(NATURAL)) {
read("JOIN"); read(JOIN);
join = readTableFilter(); join = readTableFilter();
Column[] tableCols = last.getTable().getColumns(); Column[] tableCols = last.getTable().getColumns();
Column[] joinCols = join.getTable().getColumns(); Column[] joinCols = join.getTable().getColumns();
...@@ -1912,7 +2137,7 @@ public class Parser { ...@@ -1912,7 +2137,7 @@ public class Parser {
procedureName); procedureName);
} }
command.setProcedure(p); command.setProcedure(p);
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
for (int i = 0;; i++) { for (int i = 0;; i++) {
command.setExpression(i, readExpression()); command.setExpression(i, readExpression());
if (!readIfMore(true)) { if (!readIfMore(true)) {
...@@ -1937,10 +2162,10 @@ public class Parser { ...@@ -1937,10 +2162,10 @@ public class Parser {
command.setExecuteCommand(true); command.setExecuteCommand(true);
} else { } else {
if (readIf("PLAN")) { if (readIf("PLAN")) {
readIf("FOR"); readIf(FOR);
} }
} }
if (isToken("SELECT") || isToken("FROM") || isToken("(") || isToken("WITH")) { if (isToken(SELECT) || isToken(FROM) || isToken(OPEN_PAREN) || isToken(WITH)) {
Query query = parseSelect(); Query query = parseSelect();
query.setNeverLazy(true); query.setNeverLazy(true);
command.setCommand(query); command.setCommand(query);
...@@ -1996,22 +2221,22 @@ public class Parser { ...@@ -1996,22 +2221,22 @@ public class Parser {
private Query parseSelectUnionExtension(Query command, int start, private Query parseSelectUnionExtension(Query command, int start,
boolean unionOnly) { boolean unionOnly) {
while (true) { while (true) {
if (readIf("UNION")) { if (readIf(UNION)) {
SelectUnion union = new SelectUnion(session, command); SelectUnion union = new SelectUnion(session, command);
if (readIf("ALL")) { if (readIf(ALL)) {
union.setUnionType(SelectUnion.UnionType.UNION_ALL); union.setUnionType(SelectUnion.UnionType.UNION_ALL);
} else { } else {
readIf("DISTINCT"); readIf(DISTINCT);
union.setUnionType(SelectUnion.UnionType.UNION); union.setUnionType(SelectUnion.UnionType.UNION);
} }
union.setRight(parseSelectSub()); union.setRight(parseSelectSub());
command = union; command = union;
} else if (readIf("MINUS") || readIf("EXCEPT")) { } else if (readIf(MINUS) || readIf(EXCEPT)) {
SelectUnion union = new SelectUnion(session, command); SelectUnion union = new SelectUnion(session, command);
union.setUnionType(SelectUnion.UnionType.EXCEPT); union.setUnionType(SelectUnion.UnionType.EXCEPT);
union.setRight(parseSelectSub()); union.setRight(parseSelectSub());
command = union; command = union;
} else if (readIf("INTERSECT")) { } else if (readIf(INTERSECT)) {
SelectUnion union = new SelectUnion(session, command); SelectUnion union = new SelectUnion(session, command);
union.setUnionType(SelectUnion.UnionType.INTERSECT); union.setUnionType(SelectUnion.UnionType.INTERSECT);
union.setRight(parseSelectSub()); union.setRight(parseSelectSub());
...@@ -2028,7 +2253,7 @@ public class Parser { ...@@ -2028,7 +2253,7 @@ public class Parser {
} }
private void parseEndOfQuery(Query command) { private void parseEndOfQuery(Query command) {
if (readIf("ORDER")) { if (readIf(ORDER)) {
read("BY"); read("BY");
Select oldSelect = currentSelect; Select oldSelect = currentSelect;
if (command instanceof Select) { if (command instanceof Select) {
...@@ -2036,7 +2261,7 @@ public class Parser { ...@@ -2036,7 +2261,7 @@ public class Parser {
} }
ArrayList<SelectOrderBy> orderList = Utils.newSmallArrayList(); ArrayList<SelectOrderBy> orderList = Utils.newSmallArrayList();
do { do {
boolean canBeNumber = !readIf("="); boolean canBeNumber = !readIf(EQUAL);
SelectOrderBy order = new SelectOrderBy(); SelectOrderBy order = new SelectOrderBy();
Expression expr = readExpression(); Expression expr = readExpression();
if (canBeNumber && expr instanceof ValueExpression && if (canBeNumber && expr instanceof ValueExpression &&
...@@ -2058,13 +2283,13 @@ public class Parser { ...@@ -2058,13 +2283,13 @@ public class Parser {
Select temp = currentSelect; Select temp = currentSelect;
currentSelect = null; currentSelect = null;
// http://sqlpro.developpez.com/SQL2008/ // http://sqlpro.developpez.com/SQL2008/
if (readIf("OFFSET")) { if (readIf(OFFSET)) {
command.setOffset(readExpression().optimize(session)); command.setOffset(readExpression().optimize(session));
if (!readIf("ROW")) { if (!readIf("ROW")) {
readIf("ROWS"); readIf("ROWS");
} }
} }
if (readIf("FETCH")) { if (readIf(FETCH)) {
if (!readIf("FIRST")) { if (!readIf("FIRST")) {
read("NEXT"); read("NEXT");
} }
...@@ -2080,13 +2305,13 @@ public class Parser { ...@@ -2080,13 +2305,13 @@ public class Parser {
read("ONLY"); read("ONLY");
} }
currentSelect = temp; currentSelect = temp;
if (readIf("LIMIT")) { if (readIf(LIMIT)) {
temp = currentSelect; temp = currentSelect;
// make sure aggregate functions will not work here // make sure aggregate functions will not work here
currentSelect = null; currentSelect = null;
Expression limit = readExpression().optimize(session); Expression limit = readExpression().optimize(session);
command.setLimit(limit); command.setLimit(limit);
if (readIf("OFFSET")) { if (readIf(OFFSET)) {
Expression offset = readExpression().optimize(session); Expression offset = readExpression().optimize(session);
command.setOffset(offset); command.setOffset(offset);
} else if (readIf(",")) { } else if (readIf(",")) {
...@@ -2102,7 +2327,7 @@ public class Parser { ...@@ -2102,7 +2327,7 @@ public class Parser {
} }
currentSelect = temp; currentSelect = temp;
} }
if (readIf("FOR")) { if (readIf(FOR)) {
if (readIf("UPDATE")) { if (readIf("UPDATE")) {
if (readIf("OF")) { if (readIf("OF")) {
do { do {
...@@ -2112,7 +2337,7 @@ public class Parser { ...@@ -2112,7 +2337,7 @@ public class Parser {
// TODO parser: select for update nowait: should not wait // TODO parser: select for update nowait: should not wait
} }
command.setForUpdate(true); command.setForUpdate(true);
} else if (readIf("READ") || readIf("FETCH")) { } else if (readIf("READ") || readIf(FETCH)) {
read("ONLY"); read("ONLY");
} }
} }
...@@ -2125,7 +2350,7 @@ public class Parser { ...@@ -2125,7 +2350,7 @@ public class Parser {
* DB2 isolation clause * DB2 isolation clause
*/ */
private void parseIsolationClause() { private void parseIsolationClause() {
if (readIf("WITH")) { if (readIf(WITH)) {
if (readIf("RR") || readIf("RS")) { if (readIf("RR") || readIf("RS")) {
// concurrent-access-resolution clause // concurrent-access-resolution clause
if (readIf("USE")) { if (readIf("USE")) {
...@@ -2144,12 +2369,12 @@ public class Parser { ...@@ -2144,12 +2369,12 @@ public class Parser {
} }
private Query parseSelectSub() { private Query parseSelectSub() {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
Query command = parseSelectUnion(); Query command = parseSelectUnion();
read(")"); read(CLOSE_PAREN);
return command; return command;
} }
if (readIf("WITH")) { if (readIf(WITH)) {
Query query; Query query;
try { try {
query = (Query) parseWith(); query = (Query) parseWith();
...@@ -2223,17 +2448,17 @@ public class Parser { ...@@ -2223,17 +2448,17 @@ public class Parser {
// SELECT TOP 1 (+?) AS A FROM TEST // SELECT TOP 1 (+?) AS A FROM TEST
Expression limit = readTerm().optimize(session); Expression limit = readTerm().optimize(session);
command.setLimit(limit); command.setLimit(limit);
} else if (readIf("LIMIT")) { } else if (readIf(LIMIT)) {
Expression offset = readTerm().optimize(session); Expression offset = readTerm().optimize(session);
command.setOffset(offset); command.setOffset(offset);
Expression limit = readTerm().optimize(session); Expression limit = readTerm().optimize(session);
command.setLimit(limit); command.setLimit(limit);
} }
currentSelect = temp; currentSelect = temp;
if (readIf("DISTINCT")) { if (readIf(DISTINCT)) {
command.setDistinct(true); command.setDistinct(true);
} else { } else {
readIf("ALL"); readIf(ALL);
} }
ArrayList<Expression> expressions = Utils.newSmallArrayList(); ArrayList<Expression> expressions = Utils.newSmallArrayList();
do { do {
...@@ -2255,9 +2480,9 @@ public class Parser { ...@@ -2255,9 +2480,9 @@ public class Parser {
private Select parseSelectSimple() { private Select parseSelectSimple() {
boolean fromFirst; boolean fromFirst;
if (readIf("SELECT")) { if (readIf(SELECT)) {
fromFirst = false; fromFirst = false;
} else if (readIf("FROM")) { } else if (readIf(FROM)) {
fromFirst = true; fromFirst = true;
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
...@@ -2269,11 +2494,11 @@ public class Parser { ...@@ -2269,11 +2494,11 @@ public class Parser {
currentPrepared = command; currentPrepared = command;
if (fromFirst) { if (fromFirst) {
parseSelectSimpleFromPart(command); parseSelectSimpleFromPart(command);
read("SELECT"); read(SELECT);
parseSelectSimpleSelectPart(command); parseSelectSimpleSelectPart(command);
} else { } else {
parseSelectSimpleSelectPart(command); parseSelectSimpleSelectPart(command);
if (!readIf("FROM")) { if (!readIf(FROM)) {
// select without FROM: convert to SELECT ... FROM // select without FROM: convert to SELECT ... FROM
// SYSTEM_RANGE(1,1) // SYSTEM_RANGE(1,1)
Table dual = getDualTable(false); Table dual = getDualTable(false);
...@@ -2285,14 +2510,14 @@ public class Parser { ...@@ -2285,14 +2510,14 @@ public class Parser {
parseSelectSimpleFromPart(command); parseSelectSimpleFromPart(command);
} }
} }
if (readIf("WHERE")) { if (readIf(WHERE)) {
Expression condition = readExpression(); Expression condition = readExpression();
command.addCondition(condition); command.addCondition(condition);
} }
// the group by is read for the outer select (or not a select) // the group by is read for the outer select (or not a select)
// so that columns that are not grouped can be used // so that columns that are not grouped can be used
currentSelect = oldSelect; currentSelect = oldSelect;
if (readIf("GROUP")) { if (readIf(GROUP)) {
read("BY"); read("BY");
command.setGroupQuery(); command.setGroupQuery();
ArrayList<Expression> list = Utils.newSmallArrayList(); ArrayList<Expression> list = Utils.newSmallArrayList();
...@@ -2303,7 +2528,7 @@ public class Parser { ...@@ -2303,7 +2528,7 @@ public class Parser {
command.setGroupBy(list); command.setGroupBy(list);
} }
currentSelect = command; currentSelect = command;
if (readIf("HAVING")) { if (readIf(HAVING)) {
command.setGroupQuery(); command.setGroupQuery();
Expression condition = readExpression(); Expression condition = readExpression();
command.setHaving(condition); command.setHaving(condition);
...@@ -2352,23 +2577,23 @@ public class Parser { ...@@ -2352,23 +2577,23 @@ public class Parser {
} }
private Expression readCondition() { private Expression readCondition() {
if (readIf("NOT")) { if (readIf(NOT)) {
return new ConditionNot(readCondition()); return new ConditionNot(readCondition());
} }
if (readIf("EXISTS")) { if (readIf(EXISTS)) {
read("("); read(OPEN_PAREN);
Query query = parseSelect(); Query query = parseSelect();
// can not reduce expression because it might be a union except // can not reduce expression because it might be a union except
// query with distinct // query with distinct
read(")"); read(CLOSE_PAREN);
return new ConditionExists(query); return new ConditionExists(query);
} }
if (readIf("INTERSECTS")) { if (readIf("INTERSECTS")) {
read("("); read(OPEN_PAREN);
Expression r1 = readConcat(); Expression r1 = readConcat();
read(","); read(",");
Expression r2 = readConcat(); Expression r2 = readConcat();
read(")"); read(CLOSE_PAREN);
return new Comparison(session, Comparison.SPATIAL_INTERSECTS, r1, return new Comparison(session, Comparison.SPATIAL_INTERSECTS, r1,
r2); r2);
} }
...@@ -2378,16 +2603,17 @@ public class Parser { ...@@ -2378,16 +2603,17 @@ public class Parser {
// TABLE TEST(ID INT DEFAULT 0 NOT NULL)) // TABLE TEST(ID INT DEFAULT 0 NOT NULL))
int backup = parseIndex; int backup = parseIndex;
boolean not = false; boolean not = false;
if (readIf("NOT")) { if (readIf(NOT)) {
not = true; not = true;
if (isToken("NULL")) { if (isToken(NULL)) {
// this really only works for NOT NULL! // this really only works for NOT NULL!
parseIndex = backup; parseIndex = backup;
currentToken = "NOT"; currentToken = "NOT";
currentTokenType = NOT;
break; break;
} }
} }
if (readIf("LIKE")) { if (readIf(LIKE)) {
Expression b = readConcat(); Expression b = readConcat();
Expression esc = null; Expression esc = null;
if (readIf("ESCAPE")) { if (readIf("ESCAPE")) {
...@@ -2411,23 +2637,23 @@ public class Parser { ...@@ -2411,23 +2637,23 @@ public class Parser {
Expression b = readConcat(); Expression b = readConcat();
recompileAlways = true; recompileAlways = true;
r = new CompareLike(database, r, b, null, true); r = new CompareLike(database, r, b, null, true);
} else if (readIf("IS")) { } else if (readIf(IS)) {
if (readIf("NOT")) { if (readIf(NOT)) {
if (readIf("NULL")) { if (readIf(NULL)) {
r = new Comparison(session, Comparison.IS_NOT_NULL, r, r = new Comparison(session, Comparison.IS_NOT_NULL, r,
null); null);
} else if (readIf("DISTINCT")) { } else if (readIf(DISTINCT)) {
read("FROM"); read(FROM);
r = new Comparison(session, Comparison.EQUAL_NULL_SAFE, r = new Comparison(session, Comparison.EQUAL_NULL_SAFE,
r, readConcat()); r, readConcat());
} else { } else {
r = new Comparison(session, r = new Comparison(session,
Comparison.NOT_EQUAL_NULL_SAFE, r, readConcat()); Comparison.NOT_EQUAL_NULL_SAFE, r, readConcat());
} }
} else if (readIf("NULL")) { } else if (readIf(NULL)) {
r = new Comparison(session, Comparison.IS_NULL, r, null); r = new Comparison(session, Comparison.IS_NULL, r, null);
} else if (readIf("DISTINCT")) { } else if (readIf(DISTINCT)) {
read("FROM"); read(FROM);
r = new Comparison(session, Comparison.NOT_EQUAL_NULL_SAFE, r = new Comparison(session, Comparison.NOT_EQUAL_NULL_SAFE,
r, readConcat()); r, readConcat());
} else { } else {
...@@ -2435,8 +2661,8 @@ public class Parser { ...@@ -2435,8 +2661,8 @@ public class Parser {
readConcat()); readConcat());
} }
} else if (readIf("IN")) { } else if (readIf("IN")) {
read("("); read(OPEN_PAREN);
if (readIf(")")) { if (readIf(CLOSE_PAREN)) {
if (database.getMode().prohibitEmptyInPredicate) { if (database.getMode().prohibitEmptyInPredicate) {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -2466,7 +2692,7 @@ public class Parser { ...@@ -2466,7 +2692,7 @@ public class Parser {
r = new ConditionIn(database, r, v); r = new ConditionIn(database, r, v);
} }
} }
read(")"); read(CLOSE_PAREN);
} }
} else if (readIf("BETWEEN")) { } else if (readIf("BETWEEN")) {
Expression low = readConcat(); Expression low = readConcat();
...@@ -2483,14 +2709,14 @@ public class Parser { ...@@ -2483,14 +2709,14 @@ public class Parser {
break; break;
} }
read(); read();
if (readIf("ALL")) { if (readIf(ALL)) {
read("("); read(OPEN_PAREN);
Query query = parseSelect(); Query query = parseSelect();
r = new ConditionInSelect(database, r, query, true, r = new ConditionInSelect(database, r, query, true,
compareType); compareType);
read(")"); read(CLOSE_PAREN);
} else if (readIf("ANY") || readIf("SOME")) { } else if (readIf("ANY") || readIf("SOME")) {
read("("); read(OPEN_PAREN);
if (currentTokenType == PARAMETER && compareType == 0) { if (currentTokenType == PARAMETER && compareType == 0) {
Parameter p = readParameter(); Parameter p = readParameter();
r = new ConditionInParameter(database, r, p); r = new ConditionInParameter(database, r, p);
...@@ -2499,11 +2725,11 @@ public class Parser { ...@@ -2499,11 +2725,11 @@ public class Parser {
r = new ConditionInSelect(database, r, query, false, r = new ConditionInSelect(database, r, query, false,
compareType); compareType);
} }
read(")"); read(CLOSE_PAREN);
} else { } else {
Expression right = readConcat(); Expression right = readConcat();
if (SysProperties.OLD_STYLE_OUTER_JOIN && if (SysProperties.OLD_STYLE_OUTER_JOIN &&
readIf("(") && readIf("+") && readIf(")")) { readIf(OPEN_PAREN) && readIf(PLUS_SIGN) && readIf(CLOSE_PAREN)) {
// support for a subset of old-fashioned Oracle outer // support for a subset of old-fashioned Oracle outer
// join with (+) // join with (+)
if (r instanceof ExpressionColumn && if (r instanceof ExpressionColumn &&
...@@ -2548,7 +2774,7 @@ public class Parser { ...@@ -2548,7 +2774,7 @@ public class Parser {
private Expression readConcat() { private Expression readConcat() {
Expression r = readSum(); Expression r = readSum();
while (true) { while (true) {
if (readIf("||")) { if (readIf(STRING_CONCAT)) {
r = new Operation(OpType.CONCAT, r, readSum()); r = new Operation(OpType.CONCAT, r, readSum());
} else if (readIf("~")) { } else if (readIf("~")) {
if (readIf("*")) { if (readIf("*")) {
...@@ -2578,9 +2804,9 @@ public class Parser { ...@@ -2578,9 +2804,9 @@ public class Parser {
private Expression readSum() { private Expression readSum() {
Expression r = readFactor(); Expression r = readFactor();
while (true) { while (true) {
if (readIf("+")) { if (readIf(PLUS_SIGN)) {
r = new Operation(OpType.PLUS, r, readFactor()); r = new Operation(OpType.PLUS, r, readFactor());
} else if (readIf("-")) { } else if (readIf(MINUS_SIGN)) {
r = new Operation(OpType.MINUS, r, readFactor()); r = new Operation(OpType.MINUS, r, readFactor());
} else { } else {
return r; return r;
...@@ -2614,7 +2840,7 @@ public class Parser { ...@@ -2614,7 +2840,7 @@ public class Parser {
r = new Aggregate(AggregateType.COUNT_ALL, null, currentSelect, r = new Aggregate(AggregateType.COUNT_ALL, null, currentSelect,
false); false);
} else { } else {
boolean distinct = readIf("DISTINCT"); boolean distinct = readIf(DISTINCT);
Expression on = readExpression(); Expression on = readExpression();
if (on instanceof Wildcard && !distinct) { if (on instanceof Wildcard && !distinct) {
// PostgreSQL compatibility: count(t.*) // PostgreSQL compatibility: count(t.*)
...@@ -2626,12 +2852,12 @@ public class Parser { ...@@ -2626,12 +2852,12 @@ public class Parser {
} }
} }
} else if (aggregateType == AggregateType.GROUP_CONCAT) { } else if (aggregateType == AggregateType.GROUP_CONCAT) {
boolean distinct = readIf("DISTINCT"); boolean distinct = readIf(DISTINCT);
if (equalsToken("GROUP_CONCAT", aggregateName)) { if (equalsToken("GROUP_CONCAT", aggregateName)) {
r = new Aggregate(AggregateType.GROUP_CONCAT, r = new Aggregate(AggregateType.GROUP_CONCAT,
readExpression(), currentSelect, distinct); readExpression(), currentSelect, distinct);
if (readIf("ORDER")) { if (readIf(ORDER)) {
read("BY"); read("BY");
r.setOrderByList(parseSimpleOrderList()); r.setOrderByList(parseSimpleOrderList());
} }
...@@ -2645,7 +2871,7 @@ public class Parser { ...@@ -2645,7 +2871,7 @@ public class Parser {
readExpression(), currentSelect, distinct); readExpression(), currentSelect, distinct);
read(","); read(",");
r.setGroupConcatSeparator(readExpression()); r.setGroupConcatSeparator(readExpression());
if (readIf("ORDER")) { if (readIf(ORDER)) {
read("BY"); read("BY");
r.setOrderByList(parseSimpleOrderList()); r.setOrderByList(parseSimpleOrderList());
} }
...@@ -2653,20 +2879,20 @@ public class Parser { ...@@ -2653,20 +2879,20 @@ public class Parser {
r = null; r = null;
} }
} else if (aggregateType == AggregateType.ARRAY_AGG) { } else if (aggregateType == AggregateType.ARRAY_AGG) {
boolean distinct = readIf("DISTINCT"); boolean distinct = readIf(DISTINCT);
r = new Aggregate(AggregateType.ARRAY_AGG, r = new Aggregate(AggregateType.ARRAY_AGG,
readExpression(), currentSelect, distinct); readExpression(), currentSelect, distinct);
if (readIf("ORDER")) { if (readIf(ORDER)) {
read("BY"); read("BY");
r.setOrderByList(parseSimpleOrderList()); r.setOrderByList(parseSimpleOrderList());
} }
} else { } else {
boolean distinct = readIf("DISTINCT"); boolean distinct = readIf(DISTINCT);
r = new Aggregate(aggregateType, readExpression(), currentSelect, r = new Aggregate(aggregateType, readExpression(), currentSelect,
distinct); distinct);
} }
read(")"); read(CLOSE_PAREN);
if (r != null) { if (r != null) {
r.setFilterCondition(readFilterCondition()); r.setFilterCondition(readFilterCondition());
} }
...@@ -2701,7 +2927,7 @@ public class Parser { ...@@ -2701,7 +2927,7 @@ public class Parser {
} }
Expression[] args; Expression[] args;
ArrayList<Expression> argList = Utils.newSmallArrayList(); ArrayList<Expression> argList = Utils.newSmallArrayList();
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
argList.add(readExpression()); argList.add(readExpression());
} while (readIfMore(true)); } while (readIfMore(true));
...@@ -2711,7 +2937,7 @@ public class Parser { ...@@ -2711,7 +2937,7 @@ public class Parser {
} }
private JavaAggregate readJavaAggregate(UserAggregate aggregate) { private JavaAggregate readJavaAggregate(UserAggregate aggregate) {
boolean distinct = readIf("DISTINCT"); boolean distinct = readIf(DISTINCT);
ArrayList<Expression> params = Utils.newSmallArrayList(); ArrayList<Expression> params = Utils.newSmallArrayList();
do { do {
params.add(readExpression()); params.add(readExpression());
...@@ -2725,10 +2951,10 @@ public class Parser { ...@@ -2725,10 +2951,10 @@ public class Parser {
private Expression readFilterCondition() { private Expression readFilterCondition() {
if (readIf("FILTER")) { if (readIf("FILTER")) {
read("("); read(OPEN_PAREN);
read("WHERE"); read(WHERE);
Expression filterCondition = readExpression(); Expression filterCondition = readExpression();
read(")"); read(CLOSE_PAREN);
return filterCondition; return filterCondition;
} }
return null; return null;
...@@ -2774,7 +3000,7 @@ public class Parser { ...@@ -2774,7 +3000,7 @@ public class Parser {
read("AS"); read("AS");
Column type = parseColumnWithType(null, false); Column type = parseColumnWithType(null, false);
function.setDataType(type); function.setDataType(type);
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.CONVERT: { case Function.CONVERT: {
...@@ -2783,13 +3009,13 @@ public class Parser { ...@@ -2783,13 +3009,13 @@ public class Parser {
function.setDataType(type); function.setDataType(type);
read(","); read(",");
function.setParameter(0, readExpression()); function.setParameter(0, readExpression());
read(")"); read(CLOSE_PAREN);
} else { } else {
function.setParameter(0, readExpression()); function.setParameter(0, readExpression());
read(","); read(",");
Column type = parseColumnWithType(null, false); Column type = parseColumnWithType(null, false);
function.setDataType(type); function.setDataType(type);
read(")"); read(CLOSE_PAREN);
} }
break; break;
} }
...@@ -2797,9 +3023,9 @@ public class Parser { ...@@ -2797,9 +3023,9 @@ public class Parser {
function.setParameter(0, function.setParameter(0,
ValueExpression.get(ValueString.get(currentToken))); ValueExpression.get(ValueString.get(currentToken)));
read(); read();
read("FROM"); read(FROM);
function.setParameter(1, readExpression()); function.setParameter(1, readExpression());
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.DATE_ADD: case Function.DATE_ADD:
...@@ -2815,7 +3041,7 @@ public class Parser { ...@@ -2815,7 +3041,7 @@ public class Parser {
function.setParameter(1, readExpression()); function.setParameter(1, readExpression());
read(","); read(",");
function.setParameter(2, readExpression()); function.setParameter(2, readExpression());
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.SUBSTRING: { case Function.SUBSTRING: {
...@@ -2826,12 +3052,12 @@ public class Parser { ...@@ -2826,12 +3052,12 @@ public class Parser {
// SUBSTRING(X FROM 1) -- Postgres // SUBSTRING(X FROM 1) -- Postgres
// SUBSTRING(X FOR 1) -- Postgres // SUBSTRING(X FOR 1) -- Postgres
function.setParameter(0, readExpression()); function.setParameter(0, readExpression());
if (readIf("FROM")) { if (readIf(FROM)) {
function.setParameter(1, readExpression()); function.setParameter(1, readExpression());
if (readIf("FOR")) { if (readIf(FOR)) {
function.setParameter(2, readExpression()); function.setParameter(2, readExpression());
} }
} else if (readIf("FOR")) { } else if (readIf(FOR)) {
function.setParameter(1, ValueExpression.get(ValueInt.get(0))); function.setParameter(1, ValueExpression.get(ValueInt.get(0)));
function.setParameter(2, readExpression()); function.setParameter(2, readExpression());
} else { } else {
...@@ -2841,7 +3067,7 @@ public class Parser { ...@@ -2841,7 +3067,7 @@ public class Parser {
function.setParameter(2, readExpression()); function.setParameter(2, readExpression());
} }
} }
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.POSITION: { case Function.POSITION: {
...@@ -2851,33 +3077,33 @@ public class Parser { ...@@ -2851,33 +3077,33 @@ public class Parser {
read("IN"); read("IN");
} }
function.setParameter(1, readExpression()); function.setParameter(1, readExpression());
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.TRIM: { case Function.TRIM: {
Expression space = null; Expression space = null;
if (readIf("LEADING")) { if (readIf("LEADING")) {
function = Function.getFunction(database, "LTRIM"); function = Function.getFunction(database, "LTRIM");
if (!readIf("FROM")) { if (!readIf(FROM)) {
space = readExpression(); space = readExpression();
read("FROM"); read(FROM);
} }
} else if (readIf("TRAILING")) { } else if (readIf("TRAILING")) {
function = Function.getFunction(database, "RTRIM"); function = Function.getFunction(database, "RTRIM");
if (!readIf("FROM")) { if (!readIf(FROM)) {
space = readExpression(); space = readExpression();
read("FROM"); read(FROM);
} }
} else if (readIf("BOTH")) { } else if (readIf("BOTH")) {
if (!readIf("FROM")) { if (!readIf(FROM)) {
space = readExpression(); space = readExpression();
read("FROM"); read(FROM);
} }
} }
Expression p0 = readExpression(); Expression p0 = readExpression();
if (readIf(",")) { if (readIf(",")) {
space = readExpression(); space = readExpression();
} else if (readIf("FROM")) { } else if (readIf(FROM)) {
space = p0; space = p0;
p0 = readExpression(); p0 = readExpression();
} }
...@@ -2885,7 +3111,7 @@ public class Parser { ...@@ -2885,7 +3111,7 @@ public class Parser {
if (space != null) { if (space != null) {
function.setParameter(1, space); function.setParameter(1, space);
} }
read(")"); read(CLOSE_PAREN);
break; break;
} }
case Function.TABLE: case Function.TABLE:
...@@ -2896,7 +3122,7 @@ public class Parser { ...@@ -2896,7 +3122,7 @@ public class Parser {
String columnName = readAliasIdentifier(); String columnName = readAliasIdentifier();
Column column = parseColumnWithType(columnName, false); Column column = parseColumnWithType(columnName, false);
columns.add(column); columns.add(column);
read("="); read(EQUAL);
function.setParameter(i, readExpression()); function.setParameter(i, readExpression());
i++; i++;
} while (readIfMore(true)); } while (readIfMore(true));
...@@ -2905,17 +3131,17 @@ public class Parser { ...@@ -2905,17 +3131,17 @@ public class Parser {
break; break;
} }
case Function.ROW_NUMBER: case Function.ROW_NUMBER:
read(")"); read(CLOSE_PAREN);
read("OVER"); read("OVER");
read("("); read(OPEN_PAREN);
read(")"); read(CLOSE_PAREN);
if (currentSelect == null && currentPrepared == null) { if (currentSelect == null && currentPrepared == null) {
throw getSyntaxError(); throw getSyntaxError();
} }
return new Rownum(currentSelect == null ? currentPrepared return new Rownum(currentSelect == null ? currentPrepared
: currentSelect); : currentSelect);
default: default:
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
int i = 0; int i = 0;
do { do {
function.setParameter(i++, readExpression()); function.setParameter(i++, readExpression());
...@@ -2927,8 +3153,8 @@ public class Parser { ...@@ -2927,8 +3153,8 @@ public class Parser {
} }
private Expression readFunctionWithoutParameters(String name) { private Expression readFunctionWithoutParameters(String name) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
read(")"); read(CLOSE_PAREN);
} }
if (database.isAllowBuiltinAliasOverride()) { if (database.isAllowBuiltinAliasOverride()) {
FunctionAlias functionAlias = database.getSchema(session.getCurrentSchemaName()).findFunction(name); FunctionAlias functionAlias = database.getSchema(session.getCurrentSchemaName()).findFunction(name);
...@@ -2976,7 +3202,7 @@ public class Parser { ...@@ -2976,7 +3202,7 @@ public class Parser {
} }
String name = readColumnIdentifier(); String name = readColumnIdentifier();
Schema s = database.findSchema(objectName); Schema s = database.findSchema(objectName);
if ((!SysProperties.OLD_STYLE_OUTER_JOIN || s != null) && readIf("(")) { if ((!SysProperties.OLD_STYLE_OUTER_JOIN || s != null) && readIf(OPEN_PAREN)) {
// only if the token before the dot is a valid schema name, // only if the token before the dot is a valid schema name,
// otherwise the old style Oracle outer join doesn't work: // otherwise the old style Oracle outer join doesn't work:
// t.x = t2.x(+) // t.x = t2.x(+)
...@@ -2991,7 +3217,7 @@ public class Parser { ...@@ -2991,7 +3217,7 @@ public class Parser {
return expr; return expr;
} }
name = readColumnIdentifier(); name = readColumnIdentifier();
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
String databaseName = schema; String databaseName = schema;
if (!equalsToken(database.getShortName(), databaseName)) { if (!equalsToken(database.getShortName(), databaseName)) {
throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1, throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1,
...@@ -3083,19 +3309,18 @@ public class Parser { ...@@ -3083,19 +3309,18 @@ public class Parser {
case PARAMETER: case PARAMETER:
r = readParameter(); r = readParameter();
break; break;
case SELECT:
case FROM:
case WITH:
r = new Subquery(parseSelect());
break;
case KEYWORD: case KEYWORD:
if (isToken("SELECT") || isToken("FROM") || isToken("WITH")) {
Query query = parseSelect();
r = new Subquery(query);
} else {
throw getSyntaxError(); throw getSyntaxError();
}
break;
case IDENTIFIER: case IDENTIFIER:
String name = currentToken; String name = currentToken;
if (currentTokenQuoted) { if (currentTokenQuoted) {
read(); read();
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
r = readFunction(null, name); r = readFunction(null, name);
} else if (readIf(".")) { } else if (readIf(".")) {
r = readTermObjectDot(name); r = readTermObjectDot(name);
...@@ -3111,7 +3336,7 @@ public class Parser { ...@@ -3111,7 +3336,7 @@ public class Parser {
// otherwise CASE(3) would be a function call, which it is // otherwise CASE(3) would be a function call, which it is
// not // not
r = readCase(); r = readCase();
} else if (readIf("(")) { } else if (readIf(OPEN_PAREN)) {
r = readFunction(null, name); r = readFunction(null, name);
} else if (equalsToken("CURRENT_USER", name)) { } else if (equalsToken("CURRENT_USER", name)) {
r = readFunctionWithoutParameters("USER"); r = readFunctionWithoutParameters("USER");
...@@ -3144,7 +3369,7 @@ public class Parser { ...@@ -3144,7 +3369,7 @@ public class Parser {
r = new ExpressionColumn(database, null, null, name); r = new ExpressionColumn(database, null, null, name);
} }
} else if (equalsToken("NEXT", name) && readIf("VALUE")) { } else if (equalsToken("NEXT", name) && readIf("VALUE")) {
read("FOR"); read(FOR);
Sequence sequence = readSequence(); Sequence sequence = readSequence();
r = new SequenceValue(sequence); r = new SequenceValue(sequence);
} else if (equalsToken("TIME", name)) { } else if (equalsToken("TIME", name)) {
...@@ -3165,7 +3390,7 @@ public class Parser { ...@@ -3165,7 +3390,7 @@ public class Parser {
r = ValueExpression.get(ValueTime.parse(time)); r = ValueExpression.get(ValueTime.parse(time));
} }
} else if (equalsToken("TIMESTAMP", name)) { } else if (equalsToken("TIMESTAMP", name)) {
if (readIf("WITH")) { if (readIf(WITH)) {
read("TIME"); read("TIME");
read("ZONE"); read("ZONE");
if (currentTokenType != VALUE if (currentTokenType != VALUE
...@@ -3236,7 +3461,7 @@ public class Parser { ...@@ -3236,7 +3461,7 @@ public class Parser {
} }
} }
break; break;
case MINUS: case MINUS_SIGN:
read(); read();
if (currentTokenType == VALUE) { if (currentTokenType == VALUE) {
r = ValueExpression.get(currentValue.negate()); r = ValueExpression.get(currentValue.negate());
...@@ -3257,20 +3482,20 @@ public class Parser { ...@@ -3257,20 +3482,20 @@ public class Parser {
r = new Operation(OpType.NEGATE, readTerm(), null); r = new Operation(OpType.NEGATE, readTerm(), null);
} }
break; break;
case PLUS: case PLUS_SIGN:
read(); read();
r = readTerm(); r = readTerm();
break; break;
case OPEN: case OPEN_PAREN:
read(); read();
if (readIf(")")) { if (readIf(CLOSE_PAREN)) {
r = new ExpressionList(new Expression[0]); r = new ExpressionList(new Expression[0]);
} else { } else {
r = readExpression(); r = readExpression();
if (readIfMore(true)) { if (readIfMore(true)) {
ArrayList<Expression> list = Utils.newSmallArrayList(); ArrayList<Expression> list = Utils.newSmallArrayList();
list.add(r); list.add(r);
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
list.add(readExpression()); list.add(readExpression());
} while (readIfMore(false)); } while (readIfMore(false));
...@@ -3289,8 +3514,8 @@ public class Parser { ...@@ -3289,8 +3514,8 @@ public class Parser {
break; break;
case ROWNUM: case ROWNUM:
read(); read();
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
read(")"); read(CLOSE_PAREN);
} }
if (currentSelect == null && currentPrepared == null) { if (currentSelect == null && currentPrepared == null) {
throw getSyntaxError(); throw getSyntaxError();
...@@ -3407,10 +3632,10 @@ public class Parser { ...@@ -3407,10 +3632,10 @@ public class Parser {
private int readInt() { private int readInt() {
boolean minus = false; boolean minus = false;
if (currentTokenType == MINUS) { if (currentTokenType == MINUS_SIGN) {
minus = true; minus = true;
read(); read();
} else if (currentTokenType == PLUS) { } else if (currentTokenType == PLUS_SIGN) {
read(); read();
} }
if (currentTokenType != VALUE) { if (currentTokenType != VALUE) {
...@@ -3427,10 +3652,10 @@ public class Parser { ...@@ -3427,10 +3652,10 @@ public class Parser {
private long readLong() { private long readLong() {
boolean minus = false; boolean minus = false;
if (currentTokenType == MINUS) { if (currentTokenType == MINUS_SIGN) {
minus = true; minus = true;
read(); read();
} else if (currentTokenType == PLUS) { } else if (currentTokenType == PLUS_SIGN) {
read(); read();
} }
if (currentTokenType != VALUE) { if (currentTokenType != VALUE) {
...@@ -3458,7 +3683,7 @@ public class Parser { ...@@ -3458,7 +3683,7 @@ public class Parser {
read(); read();
return result; return result;
} }
if (readIf("ON")) { if (readIf(ON)) {
return true; return true;
} else if (readIf("OFF")) { } else if (readIf("OFF")) {
return false; return false;
...@@ -3539,6 +3764,14 @@ public class Parser { ...@@ -3539,6 +3764,14 @@ public class Parser {
read(); read();
} }
private void read(int tokenType) {
if (tokenType != currentTokenType) {
addExpected(tokenType);
throw getSyntaxError();
}
read();
}
private boolean readIf(String token) { private boolean readIf(String token) {
if (!currentTokenQuoted && equalsToken(token, currentToken)) { if (!currentTokenQuoted && equalsToken(token, currentToken)) {
read(); read();
...@@ -3548,6 +3781,15 @@ public class Parser { ...@@ -3548,6 +3781,15 @@ public class Parser {
return false; return false;
} }
private boolean readIf(int tokenType) {
if (tokenType == currentTokenType) {
read();
return true;
}
addExpected(tokenType);
return false;
}
private boolean isToken(String token) { private boolean isToken(String token) {
if (!currentTokenQuoted && equalsToken(token, currentToken)) { if (!currentTokenQuoted && equalsToken(token, currentToken)) {
return true; return true;
...@@ -3556,6 +3798,14 @@ public class Parser { ...@@ -3556,6 +3798,14 @@ public class Parser {
return false; return false;
} }
private boolean isToken(int tokenType) {
if (tokenType == currentTokenType) {
return true;
}
addExpected(tokenType);
return false;
}
private boolean equalsToken(String a, String b) { private boolean equalsToken(String a, String b) {
if (a == null) { if (a == null) {
return b == null; return b == null;
...@@ -3581,6 +3831,12 @@ public class Parser { ...@@ -3581,6 +3831,12 @@ public class Parser {
} }
} }
private void addExpected(int tokenType) {
if (expectedList != null) {
expectedList.add(TOKENS[tokenType]);
}
}
private void read() { private void read() {
currentTokenQuoted = false; currentTokenQuoted = false;
if (expectedList != null) { if (expectedList != null) {
...@@ -4085,9 +4341,9 @@ public class Parser { ...@@ -4085,9 +4341,9 @@ public class Parser {
case '@': case '@':
return AT; return AT;
case '+': case '+':
return PLUS; return PLUS_SIGN;
case '-': case '-':
return MINUS; return MINUS_SIGN;
case '{': case '{':
case '}': case '}':
case '*': case '*':
...@@ -4101,9 +4357,9 @@ public class Parser { ...@@ -4101,9 +4357,9 @@ public class Parser {
case '~': case '~':
return KEYWORD; return KEYWORD;
case '(': case '(':
return OPEN; return OPEN_PAREN;
case ')': case ')':
return CLOSE; return CLOSE_PAREN;
case '<': case '<':
return SMALLER; return SMALLER;
case '>': case '>':
...@@ -4242,21 +4498,21 @@ public class Parser { ...@@ -4242,21 +4498,21 @@ public class Parser {
read("AS"); read("AS");
read("IDENTITY"); read("IDENTITY");
long start = 1, increment = 1; long start = 1, increment = 1;
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
read("START"); read("START");
readIf("WITH"); readIf(WITH);
start = readLong(); start = readLong();
readIf(","); readIf(",");
if (readIf("INCREMENT")) { if (readIf("INCREMENT")) {
readIf("BY"); readIf("BY");
increment = readLong(); increment = readLong();
} }
read(")"); read(CLOSE_PAREN);
} }
column.setPrimaryKey(true); column.setPrimaryKey(true);
column.setAutoIncrement(true, start, increment); column.setAutoIncrement(true, start, increment);
} }
if (readIf("ON")) { if (readIf(ON)) {
read("UPDATE"); read("UPDATE");
Expression onUpdateExpression = readExpression(); Expression onUpdateExpression = readExpression();
column.setOnUpdateExpression(session, onUpdateExpression); column.setOnUpdateExpression(session, onUpdateExpression);
...@@ -4292,19 +4548,19 @@ public class Parser { ...@@ -4292,19 +4548,19 @@ public class Parser {
private void parseAutoIncrement(Column column) { private void parseAutoIncrement(Column column) {
long start = 1, increment = 1; long start = 1, increment = 1;
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
start = readLong(); start = readLong();
if (readIf(",")) { if (readIf(",")) {
increment = readLong(); increment = readLong();
} }
read(")"); read(CLOSE_PAREN);
} }
column.setAutoIncrement(true, start, increment); column.setAutoIncrement(true, start, increment);
} }
private String readCommentIf() { private String readCommentIf() {
if (readIf("COMMENT")) { if (readIf("COMMENT")) {
readIf("IS"); readIf(IS);
return readString(); return readString();
} }
return null; return null;
...@@ -4327,12 +4583,12 @@ public class Parser { ...@@ -4327,12 +4583,12 @@ public class Parser {
original += " VARYING"; original += " VARYING";
} }
} else if (readIf("TIME")) { } else if (readIf("TIME")) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
originalScale = readNonNegativeInt(); originalScale = readNonNegativeInt();
if (originalScale > ValueTime.MAXIMUM_SCALE) { if (originalScale > ValueTime.MAXIMUM_SCALE) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(originalScale)); throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(originalScale));
} }
read(")"); read(CLOSE_PAREN);
} }
if (readIf("WITHOUT")) { if (readIf("WITHOUT")) {
read("TIME"); read("TIME");
...@@ -4340,7 +4596,7 @@ public class Parser { ...@@ -4340,7 +4596,7 @@ public class Parser {
original += " WITHOUT TIME ZONE"; original += " WITHOUT TIME ZONE";
} }
} else if (readIf("TIMESTAMP")) { } else if (readIf("TIMESTAMP")) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
originalScale = readNonNegativeInt(); originalScale = readNonNegativeInt();
// Allow non-standard TIMESTAMP(..., ...) syntax // Allow non-standard TIMESTAMP(..., ...) syntax
if (readIf(",")) { if (readIf(",")) {
...@@ -4349,9 +4605,9 @@ public class Parser { ...@@ -4349,9 +4605,9 @@ public class Parser {
if (originalScale > ValueTimestamp.MAXIMUM_SCALE) { if (originalScale > ValueTimestamp.MAXIMUM_SCALE) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(originalScale)); throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(originalScale));
} }
read(")"); read(CLOSE_PAREN);
} }
if (readIf("WITH")) { if (readIf(WITH)) {
read("TIME"); read("TIME");
read("ZONE"); read("ZONE");
original += " WITH TIME ZONE"; original += " WITH TIME ZONE";
...@@ -4431,13 +4687,13 @@ public class Parser { ...@@ -4431,13 +4687,13 @@ public class Parser {
break; break;
} }
} else if (original.equals("DATETIME") || original.equals("DATETIME2")) { } else if (original.equals("DATETIME") || original.equals("DATETIME2")) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
originalScale = readNonNegativeInt(); originalScale = readNonNegativeInt();
if (originalScale > ValueTime.MAXIMUM_SCALE) { if (originalScale > ValueTime.MAXIMUM_SCALE) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION,
Integer.toString(originalScale)); Integer.toString(originalScale));
} }
read(")"); read(CLOSE_PAREN);
scale = originalScale; scale = originalScale;
original = original + '(' + originalScale + ')'; original = original + '(' + originalScale + ')';
precision = displaySize = ValueTimestamp.getDisplaySize(originalScale); precision = displaySize = ValueTimestamp.getDisplaySize(originalScale);
...@@ -4446,7 +4702,7 @@ public class Parser { ...@@ -4446,7 +4702,7 @@ public class Parser {
scale = 0; scale = 0;
precision = displaySize = ValueTimestamp.getDisplaySize(0); precision = displaySize = ValueTimestamp.getDisplaySize(0);
} }
} else if (readIf("(")) { } else if (readIf(OPEN_PAREN)) {
if (!readIf("MAX")) { if (!readIf("MAX")) {
long p = readLong(); long p = readLong();
if (readIf("K")) { if (readIf("K")) {
...@@ -4476,12 +4732,12 @@ public class Parser { ...@@ -4476,12 +4732,12 @@ public class Parser {
displaySize = MathUtils.convertLongToInt(precision); displaySize = MathUtils.convertLongToInt(precision);
original += ")"; original += ")";
} }
read(")"); read(CLOSE_PAREN);
} }
} else if (dataType.type == Value.DOUBLE && original.equals("FLOAT")) { } else if (dataType.type == Value.DOUBLE && original.equals("FLOAT")) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
int p = readNonNegativeInt(); int p = readNonNegativeInt();
read(")"); read(CLOSE_PAREN);
if (p > 53) { if (p > 53) {
throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(p)); throw DbException.get(ErrorCode.INVALID_VALUE_SCALE_PRECISION, Integer.toString(p));
} }
...@@ -4491,7 +4747,7 @@ public class Parser { ...@@ -4491,7 +4747,7 @@ public class Parser {
original = original + '(' + p + ')'; original = original + '(' + p + ')';
} }
} else if (dataType.type == Value.ENUM) { } else if (dataType.type == Value.ENUM) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
java.util.List<String> enumeratorList = new ArrayList<>(); java.util.List<String> enumeratorList = new ArrayList<>();
original += '('; original += '(';
String enumerator0 = readString(); String enumerator0 = readString();
...@@ -4511,13 +4767,13 @@ public class Parser { ...@@ -4511,13 +4767,13 @@ public class Parser {
} catch (DbException e) { } catch (DbException e) {
throw e.addSQL(original); throw e.addSQL(original);
} }
} else if (readIf("(")) { } else if (readIf(OPEN_PAREN)) {
// Support for MySQL: INT(11), MEDIUMINT(8) and so on. // Support for MySQL: INT(11), MEDIUMINT(8) and so on.
// Just ignore the precision. // Just ignore the precision.
readNonNegativeInt(); readNonNegativeInt();
read(")"); read(CLOSE_PAREN);
} }
if (readIf("FOR")) { if (readIf(FOR)) {
read("BIT"); read("BIT");
read("DATA"); read("DATA");
if (dataType.type == Value.STRING) { if (dataType.type == Value.STRING) {
...@@ -4624,19 +4880,19 @@ public class Parser { ...@@ -4624,19 +4880,19 @@ public class Parser {
String indexName = null; String indexName = null;
Schema oldSchema = null; Schema oldSchema = null;
boolean ifNotExists = false; boolean ifNotExists = false;
if (readIf("PRIMARY")) { if (readIf(PRIMARY)) {
read("KEY"); read("KEY");
if (readIf("HASH")) { if (readIf("HASH")) {
hash = true; hash = true;
} }
primaryKey = true; primaryKey = true;
if (!isToken("ON")) { if (!isToken(ON)) {
ifNotExists = readIfNotExists(); ifNotExists = readIfNotExists();
indexName = readIdentifierWithSchema(null); indexName = readIdentifierWithSchema(null);
oldSchema = getSchema(); oldSchema = getSchema();
} }
} else { } else {
if (readIf("UNIQUE")) { if (readIf(UNIQUE)) {
unique = true; unique = true;
} }
if (readIf("HASH")) { if (readIf("HASH")) {
...@@ -4646,7 +4902,7 @@ public class Parser { ...@@ -4646,7 +4902,7 @@ public class Parser {
spatial = true; spatial = true;
} }
if (readIf("INDEX")) { if (readIf("INDEX")) {
if (!isToken("ON")) { if (!isToken(ON)) {
ifNotExists = readIfNotExists(); ifNotExists = readIfNotExists();
indexName = readIdentifierWithSchema(null); indexName = readIdentifierWithSchema(null);
oldSchema = getSchema(); oldSchema = getSchema();
...@@ -4655,7 +4911,7 @@ public class Parser { ...@@ -4655,7 +4911,7 @@ public class Parser {
throw getSyntaxError(); throw getSyntaxError();
} }
} }
read("ON"); read(ON);
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
checkSchema(oldSchema); checkSchema(oldSchema);
CreateIndex command = new CreateIndex(session, getSchema()); CreateIndex command = new CreateIndex(session, getSchema());
...@@ -4665,7 +4921,7 @@ public class Parser { ...@@ -4665,7 +4921,7 @@ public class Parser {
command.setUnique(unique); command.setUnique(unique);
command.setIndexName(indexName); command.setIndexName(indexName);
command.setComment(readCommentIf()); command.setComment(readCommentIf());
read("("); read(OPEN_PAREN);
command.setIndexColumns(parseIndexColumnList()); command.setIndexColumns(parseIndexColumnList());
if (readIf("USING")) { if (readIf("USING")) {
...@@ -4696,7 +4952,7 @@ public class Parser { ...@@ -4696,7 +4952,7 @@ public class Parser {
* @return true if we expect to see a TABLE clause * @return true if we expect to see a TABLE clause
*/ */
private boolean addRoleOrRight(GrantRevoke command) { private boolean addRoleOrRight(GrantRevoke command) {
if (readIf("SELECT")) { if (readIf(SELECT)) {
command.addRight(Right.SELECT); command.addRight(Right.SELECT);
return true; return true;
} else if (readIf("DELETE")) { } else if (readIf("DELETE")) {
...@@ -4708,7 +4964,7 @@ public class Parser { ...@@ -4708,7 +4964,7 @@ public class Parser {
} else if (readIf("UPDATE")) { } else if (readIf("UPDATE")) {
command.addRight(Right.UPDATE); command.addRight(Right.UPDATE);
return true; return true;
} else if (readIf("ALL")) { } else if (readIf(ALL)) {
command.addRight(Right.ALL); command.addRight(Right.ALL);
return true; return true;
} else if (readIf("ALTER")) { } else if (readIf("ALTER")) {
...@@ -4741,7 +4997,7 @@ public class Parser { ...@@ -4741,7 +4997,7 @@ public class Parser {
} }
} }
if (tableClauseExpected) { if (tableClauseExpected) {
if (readIf("ON")) { if (readIf(ON)) {
if (readIf("SCHEMA")) { if (readIf("SCHEMA")) {
Schema schema = database.getSchema(readAliasIdentifier()); Schema schema = database.getSchema(readAliasIdentifier());
command.setSchema(schema); command.setSchema(schema);
...@@ -4756,7 +5012,7 @@ public class Parser { ...@@ -4756,7 +5012,7 @@ public class Parser {
if (operationType == CommandInterface.GRANT) { if (operationType == CommandInterface.GRANT) {
read("TO"); read("TO");
} else { } else {
read("FROM"); read(FROM);
} }
command.setGranteeName(readUniqueIdentifier()); command.setGranteeName(readUniqueIdentifier());
return command; return command;
...@@ -4783,7 +5039,7 @@ public class Parser { ...@@ -4783,7 +5039,7 @@ public class Parser {
do { do {
int i = 0; int i = 0;
ArrayList<Expression> row = Utils.newSmallArrayList(); ArrayList<Expression> row = Utils.newSmallArrayList();
boolean multiColumn = readIf("("); boolean multiColumn = readIf(OPEN_PAREN);
do { do {
Expression expr = readExpression(); Expression expr = readExpression();
expr = expr.optimize(session); expr = expr.optimize(session);
...@@ -4874,7 +5130,7 @@ public class Parser { ...@@ -4874,7 +5130,7 @@ public class Parser {
} else { } else {
command.setAuthorization(session.getUser().getName()); command.setAuthorization(session.getUser().getName());
} }
if (readIf("WITH")) { if (readIf(WITH)) {
command.setTableEngineParams(readTableEngineParams()); command.setTableEngineParams(readTableEngineParams());
} }
return command; return command;
...@@ -4896,7 +5152,7 @@ public class Parser { ...@@ -4896,7 +5152,7 @@ public class Parser {
command.setSequenceName(sequenceName); command.setSequenceName(sequenceName);
while (true) { while (true) {
if (readIf("START")) { if (readIf("START")) {
readIf("WITH"); readIf(WITH);
command.setStartWith(readExpression()); command.setStartWith(readExpression());
} else if (readIf("INCREMENT")) { } else if (readIf("INCREMENT")) {
readIf("BY"); readIf("BY");
...@@ -4931,7 +5187,7 @@ public class Parser { ...@@ -4931,7 +5187,7 @@ public class Parser {
command.setCacheSize(ValueExpression.get(ValueLong.get(1))); command.setCacheSize(ValueExpression.get(ValueLong.get(1)));
} else if (readIf("BELONGS_TO_TABLE")) { } else if (readIf("BELONGS_TO_TABLE")) {
command.setBelongsToTable(true); command.setBelongsToTable(true);
} else if (readIf("ORDER")) { } else if (readIf(ORDER)) {
// Oracle compatibility // Oracle compatibility
} else { } else {
break; break;
...@@ -4942,8 +5198,8 @@ public class Parser { ...@@ -4942,8 +5198,8 @@ public class Parser {
private boolean readIfNotExists() { private boolean readIfNotExists() {
if (readIf("IF")) { if (readIf("IF")) {
read("NOT"); read(NOT);
read("EXISTS"); read(EXISTS);
return true; return true;
} }
return false; return false;
...@@ -4983,7 +5239,7 @@ public class Parser { ...@@ -4983,7 +5239,7 @@ public class Parser {
command.setName(name); command.setName(name);
command.setSchema(getSchema()); command.setSchema(getSchema());
command.setIfNotExists(ifNotExists); command.setIfNotExists(ifNotExists);
read("FOR"); read(FOR);
command.setJavaClassMethod(readUniqueIdentifier()); command.setJavaClassMethod(readUniqueIdentifier());
return command; return command;
} }
...@@ -4994,7 +5250,7 @@ public class Parser { ...@@ -4994,7 +5250,7 @@ public class Parser {
command.setTypeName(readUniqueIdentifier()); command.setTypeName(readUniqueIdentifier());
read("AS"); read("AS");
Column col = parseColumnForTable("VALUE", true, false); Column col = parseColumnForTable("VALUE", true, false);
if (readIf("CHECK")) { if (readIf(CHECK)) {
Expression expr = readExpression(); Expression expr = readExpression();
col.addCheckConstraint(session, expr); col.addCheckConstraint(session, expr);
} }
...@@ -5030,7 +5286,7 @@ public class Parser { ...@@ -5030,7 +5286,7 @@ public class Parser {
typeMask |= Trigger.UPDATE; typeMask |= Trigger.UPDATE;
} else if (readIf("DELETE")) { } else if (readIf("DELETE")) {
typeMask |= Trigger.DELETE; typeMask |= Trigger.DELETE;
} else if (readIf("SELECT")) { } else if (readIf(SELECT)) {
typeMask |= Trigger.SELECT; typeMask |= Trigger.SELECT;
} else if (readIf("ROLLBACK")) { } else if (readIf("ROLLBACK")) {
onRollback = true; onRollback = true;
...@@ -5040,7 +5296,7 @@ public class Parser { ...@@ -5040,7 +5296,7 @@ public class Parser {
} while (readIf(",") } while (readIf(",")
|| (database.getMode().getEnum() == ModeEnum.PostgreSQL || (database.getMode().getEnum() == ModeEnum.PostgreSQL
&& readIf("OR"))); && readIf("OR")));
read("ON"); read(ON);
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
checkSchema(schema); checkSchema(schema);
CreateTrigger command = new CreateTrigger(session, getSchema()); CreateTrigger command = new CreateTrigger(session, getSchema());
...@@ -5052,7 +5308,7 @@ public class Parser { ...@@ -5052,7 +5308,7 @@ public class Parser {
command.setOnRollback(onRollback); command.setOnRollback(onRollback);
command.setTypeMask(typeMask); command.setTypeMask(typeMask);
command.setTableName(tableName); command.setTableName(tableName);
if (readIf("FOR")) { if (readIf(FOR)) {
read("EACH"); read("EACH");
read("ROW"); read("ROW");
command.setRowBased(true); command.setRowBased(true);
...@@ -5119,7 +5375,7 @@ public class Parser { ...@@ -5119,7 +5375,7 @@ public class Parser {
if (readIf("AS")) { if (readIf("AS")) {
command.setSource(readString()); command.setSource(readString());
} else { } else {
read("FOR"); read(FOR);
command.setJavaClassMethod(readUniqueIdentifier()); command.setJavaClassMethod(readUniqueIdentifier());
} }
return command; return command;
...@@ -5144,7 +5400,7 @@ public class Parser { ...@@ -5144,7 +5400,7 @@ public class Parser {
// used in setCteCleanups. // used in setCteCleanups.
Collections.reverse(viewsCreated); Collections.reverse(viewsCreated);
if (isToken("SELECT")) { if (isToken(SELECT)) {
Query query = parseSelectUnion(); Query query = parseSelectUnion();
query.setPrepareAlways(true); query.setPrepareAlways(true);
query.setNeverLazy(true); query.setNeverLazy(true);
...@@ -5190,7 +5446,7 @@ public class Parser { ...@@ -5190,7 +5446,7 @@ public class Parser {
// column names are now optional - they can be inferred from the named // column names are now optional - they can be inferred from the named
// query, if not supplied by user // query, if not supplied by user
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
cols = parseColumnList(); cols = parseColumnList();
for (String c : cols) { for (String c : cols) {
// we don't really know the type of the column, so STRING will // we don't really know the type of the column, so STRING will
...@@ -5237,12 +5493,12 @@ public class Parser { ...@@ -5237,12 +5493,12 @@ public class Parser {
String[] querySQLOutput = {null}; String[] querySQLOutput = {null};
try { try {
read("AS"); read("AS");
read("("); read(OPEN_PAREN);
Query withQuery = parseSelect(); Query withQuery = parseSelect();
if (!isTemporary) { if (!isTemporary) {
withQuery.session = session; withQuery.session = session;
} }
read(")"); read(CLOSE_PAREN);
columnTemplateList = TableView.createQueryColumnTemplateList(cols, withQuery, querySQLOutput); columnTemplateList = TableView.createQueryColumnTemplateList(cols, withQuery, querySQLOutput);
} finally { } finally {
...@@ -5317,7 +5573,7 @@ public class Parser { ...@@ -5317,7 +5573,7 @@ public class Parser {
command.setOrReplace(orReplace); command.setOrReplace(orReplace);
command.setForce(force); command.setForce(force);
command.setTableExpression(isTableExpression); command.setTableExpression(isTableExpression);
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
String[] cols = parseColumnList(); String[] cols = parseColumnList();
command.setColumnNames(cols); command.setColumnNames(cols);
} }
...@@ -5442,7 +5698,7 @@ public class Parser { ...@@ -5442,7 +5698,7 @@ public class Parser {
command.setIfExists(ifExists); command.setIfExists(ifExists);
while (true) { while (true) {
if (readIf("RESTART")) { if (readIf("RESTART")) {
read("WITH"); read(WITH);
command.setStartWith(readExpression()); command.setStartWith(readExpression());
} else if (readIf("INCREMENT")) { } else if (readIf("INCREMENT")) {
read("BY"); read("BY");
...@@ -5511,9 +5767,9 @@ public class Parser { ...@@ -5511,9 +5767,9 @@ public class Parser {
command.setType(CommandInterface.ALTER_USER_ADMIN); command.setType(CommandInterface.ALTER_USER_ADMIN);
User user = database.getUser(userName); User user = database.getUser(userName);
command.setUser(user); command.setUser(user);
if (readIf("TRUE")) { if (readIf(TRUE)) {
command.setAdmin(true); command.setAdmin(true);
} else if (readIf("FALSE")) { } else if (readIf(FALSE)) {
command.setAdmin(false); command.setAdmin(false);
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
...@@ -5524,13 +5780,13 @@ public class Parser { ...@@ -5524,13 +5780,13 @@ public class Parser {
} }
private void readIfEqualOrTo() { private void readIfEqualOrTo() {
if (!readIf("=")) { if (!readIf(EQUAL)) {
readIf("TO"); readIf("TO");
} }
} }
private Prepared parseSet() { private Prepared parseSet() {
if (readIf("@")) { if (readIf(AT)) {
Set command = new Set(session, SetTypes.VARIABLE); Set command = new Set(session, SetTypes.VARIABLE);
command.setString(readAliasIdentifier()); command.setString(readAliasIdentifier());
readIfEqualOrTo(); readIfEqualOrTo();
...@@ -5612,7 +5868,7 @@ public class Parser { ...@@ -5612,7 +5868,7 @@ public class Parser {
Set command = new Set(session, SetTypes.ALLOW_LITERALS); Set command = new Set(session, SetTypes.ALLOW_LITERALS);
if (readIf("NONE")) { if (readIf("NONE")) {
command.setInt(Constants.ALLOW_LITERALS_NONE); command.setInt(Constants.ALLOW_LITERALS_NONE);
} else if (readIf("ALL")) { } else if (readIf(ALL)) {
command.setInt(Constants.ALLOW_LITERALS_ALL); command.setInt(Constants.ALLOW_LITERALS_ALL);
} else if (readIf("NUMBERS")) { } else if (readIf("NUMBERS")) {
command.setInt(Constants.ALLOW_LITERALS_NUMBERS); command.setInt(Constants.ALLOW_LITERALS_NUMBERS);
...@@ -5770,7 +6026,7 @@ public class Parser { ...@@ -5770,7 +6026,7 @@ public class Parser {
throw DbException.getInvalidValueException("collation", name); throw DbException.getInvalidValueException("collation", name);
} }
if (readIf("STRENGTH")) { if (readIf("STRENGTH")) {
if (readIf("PRIMARY")) { if (readIf(PRIMARY)) {
command.setInt(Collator.PRIMARY); command.setInt(Collator.PRIMARY);
} else if (readIf("SECONDARY")) { } else if (readIf("SECONDARY")) {
command.setInt(Collator.SECONDARY); command.setInt(Collator.SECONDARY);
...@@ -5804,7 +6060,7 @@ public class Parser { ...@@ -5804,7 +6060,7 @@ public class Parser {
private RunScriptCommand parseRunScript() { private RunScriptCommand parseRunScript() {
RunScriptCommand command = new RunScriptCommand(session); RunScriptCommand command = new RunScriptCommand(session);
read("FROM"); read(FROM);
command.setFileNameExpr(readExpression()); command.setFileNameExpr(readExpression());
if (readIf("COMPRESSION")) { if (readIf("COMPRESSION")) {
command.setCompressionAlgorithm(readUniqueIdentifier()); command.setCompressionAlgorithm(readUniqueIdentifier());
...@@ -5988,7 +6244,7 @@ public class Parser { ...@@ -5988,7 +6244,7 @@ public class Parser {
schema, type, value); schema, type, value);
command.setTableName(tableName); command.setTableName(tableName);
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
if (readIf("CHECK")) { if (readIf(CHECK)) {
command.setCheckExisting(true); command.setCheckExisting(true);
} else if (readIf("NOCHECK")) { } else if (readIf("NOCHECK")) {
command.setCheckExisting(false); command.setCheckExisting(false);
...@@ -6007,7 +6263,7 @@ public class Parser { ...@@ -6007,7 +6263,7 @@ public class Parser {
String newName = readColumnIdentifier(); String newName = readColumnIdentifier();
command.setNewColumnName(newName); command.setNewColumnName(newName);
return command; return command;
} else if (readIf("CONSTRAINT")) { } else if (readIf(CONSTRAINT)) {
String constraintName = readIdentifierWithSchema(schema.getName()); String constraintName = readIdentifierWithSchema(schema.getName());
checkSchema(schema); checkSchema(schema);
read("TO"); read("TO");
...@@ -6030,7 +6286,7 @@ public class Parser { ...@@ -6030,7 +6286,7 @@ public class Parser {
return command; return command;
} }
} else if (readIf("DROP")) { } else if (readIf("DROP")) {
if (readIf("CONSTRAINT")) { if (readIf(CONSTRAINT)) {
boolean ifExists = readIfExists(false); boolean ifExists = readIfExists(false);
String constraintName = readIdentifierWithSchema(schema.getName()); String constraintName = readIdentifierWithSchema(schema.getName());
ifExists = readIfExists(ifExists); ifExists = readIfExists(ifExists);
...@@ -6039,7 +6295,7 @@ public class Parser { ...@@ -6039,7 +6295,7 @@ public class Parser {
session, getSchema(), ifExists); session, getSchema(), ifExists);
command.setConstraintName(constraintName); command.setConstraintName(constraintName);
return commandIfTableExists(schema, tableName, ifTableExists, command); return commandIfTableExists(schema, tableName, ifTableExists, command);
} else if (readIf("FOREIGN")) { } else if (readIf(FOREIGN)) {
// MySQL compatibility // MySQL compatibility
read("KEY"); read("KEY");
String constraintName = readIdentifierWithSchema(schema.getName()); String constraintName = readIdentifierWithSchema(schema.getName());
...@@ -6063,7 +6319,7 @@ public class Parser { ...@@ -6063,7 +6319,7 @@ public class Parser {
command = dropCommand; command = dropCommand;
} }
return commandIfTableExists(schema, tableName, ifTableExists, command); return commandIfTableExists(schema, tableName, ifTableExists, command);
} else if (readIf("PRIMARY")) { } else if (readIf(PRIMARY)) {
read("KEY"); read("KEY");
Table table = tableIfTableExists(schema, tableName, ifTableExists); Table table = tableIfTableExists(schema, tableName, ifTableExists);
if (table == null) { if (table == null) {
...@@ -6079,7 +6335,7 @@ public class Parser { ...@@ -6079,7 +6335,7 @@ public class Parser {
ArrayList<Column> columnsToRemove = new ArrayList<>(); ArrayList<Column> columnsToRemove = new ArrayList<>();
Table table = tableIfTableExists(schema, tableName, ifTableExists); Table table = tableIfTableExists(schema, tableName, ifTableExists);
// For Oracle compatibility - open bracket required // For Oracle compatibility - open bracket required
boolean openingBracketDetected = readIf("("); boolean openingBracketDetected = readIf(OPEN_PAREN);
do { do {
String columnName = readColumnIdentifier(); String columnName = readColumnIdentifier();
if (table != null) { if (table != null) {
...@@ -6091,7 +6347,7 @@ public class Parser { ...@@ -6091,7 +6347,7 @@ public class Parser {
} while (readIf(",")); } while (readIf(","));
if (openingBracketDetected) { if (openingBracketDetected) {
// For Oracle compatibility - close bracket // For Oracle compatibility - close bracket
read(")"); read(CLOSE_PAREN);
} }
if (table == null || columnsToRemove.isEmpty()) { if (table == null || columnsToRemove.isEmpty()) {
return new NoOperation(session); return new NoOperation(session);
...@@ -6123,7 +6379,7 @@ public class Parser { ...@@ -6123,7 +6379,7 @@ public class Parser {
// MySQL compatibility (optional) // MySQL compatibility (optional)
readIf("COLUMN"); readIf("COLUMN");
// Oracle specifies (but will not require) an opening parenthesis // Oracle specifies (but will not require) an opening parenthesis
boolean hasOpeningBracket = readIf("("); boolean hasOpeningBracket = readIf(OPEN_PAREN);
String columnName = readColumnIdentifier(); String columnName = readColumnIdentifier();
AlterTableAlterColumn command; AlterTableAlterColumn command;
NullConstraintType nullConstraint = parseNotNullConstraint(); NullConstraintType nullConstraint = parseNotNullConstraint();
...@@ -6149,7 +6405,7 @@ public class Parser { ...@@ -6149,7 +6405,7 @@ public class Parser {
"Internal Error - unhandled case: " + nullConstraint.name()); "Internal Error - unhandled case: " + nullConstraint.name());
} }
if(hasOpeningBracket) { if(hasOpeningBracket) {
read(")"); read(CLOSE_PAREN);
} }
return command; return command;
} else if (readIf("ALTER")) { } else if (readIf("ALTER")) {
...@@ -6178,7 +6434,7 @@ public class Parser { ...@@ -6178,7 +6434,7 @@ public class Parser {
command.setDefaultExpression(null); command.setDefaultExpression(null);
return command; return command;
} }
if (readIf("ON")) { if (readIf(ON)) {
read("UPDATE"); read("UPDATE");
AlterTableAlterColumn command = new AlterTableAlterColumn(session, schema); AlterTableAlterColumn command = new AlterTableAlterColumn(session, schema);
command.setTableName(tableName); command.setTableName(tableName);
...@@ -6188,8 +6444,8 @@ public class Parser { ...@@ -6188,8 +6444,8 @@ public class Parser {
command.setDefaultExpression(null); command.setDefaultExpression(null);
return command; return command;
} }
read("NOT"); read(NOT);
read("NULL"); read(NULL);
AlterTableAlterColumn command = new AlterTableAlterColumn( AlterTableAlterColumn command = new AlterTableAlterColumn(
session, schema); session, schema);
command.setTableName(tableName); command.setTableName(tableName);
...@@ -6226,7 +6482,7 @@ public class Parser { ...@@ -6226,7 +6482,7 @@ public class Parser {
Expression defaultExpression = readExpression(); Expression defaultExpression = readExpression();
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT);
command.setDefaultExpression(defaultExpression); command.setDefaultExpression(defaultExpression);
} else if (readIf("ON")) { } else if (readIf(ON)) {
read("UPDATE"); read("UPDATE");
Expression onUpdateExpression = readExpression(); Expression onUpdateExpression = readExpression();
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_ON_UPDATE); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_ON_UPDATE);
...@@ -6245,7 +6501,7 @@ public class Parser { ...@@ -6245,7 +6501,7 @@ public class Parser {
} }
return command; return command;
} else if (readIf("RESTART")) { } else if (readIf("RESTART")) {
readIf("WITH"); readIf(WITH);
Expression start = readExpression(); Expression start = readExpression();
AlterSequence command = new AlterSequence(session, schema); AlterSequence command = new AlterSequence(session, schema);
command.setColumn(column); command.setColumn(column);
...@@ -6312,7 +6568,7 @@ public class Parser { ...@@ -6312,7 +6568,7 @@ public class Parser {
command.setType(CommandInterface.ALTER_TABLE_ADD_COLUMN); command.setType(CommandInterface.ALTER_TABLE_ADD_COLUMN);
command.setTableName(tableName); command.setTableName(tableName);
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
command.setIfNotExists(false); command.setIfNotExists(false);
do { do {
parseTableColumnDefinition(command, schema, tableName); parseTableColumnDefinition(command, schema, tableName);
...@@ -6342,7 +6598,7 @@ public class Parser { ...@@ -6342,7 +6598,7 @@ public class Parser {
return ConstraintActionType.RESTRICT; return ConstraintActionType.RESTRICT;
} }
read("SET"); read("SET");
if (readIf("NULL")) { if (readIf(NULL)) {
return ConstraintActionType.SET_NULL; return ConstraintActionType.SET_NULL;
} }
read("DEFAULT"); read("DEFAULT");
...@@ -6365,14 +6621,14 @@ public class Parser { ...@@ -6365,14 +6621,14 @@ public class Parser {
boolean ifNotExists = false; boolean ifNotExists = false;
boolean allowIndexDefinition = database.getMode().indexDefinitionInCreateTable; boolean allowIndexDefinition = database.getMode().indexDefinitionInCreateTable;
boolean allowAffinityKey = database.getMode().allowAffinityKey; boolean allowAffinityKey = database.getMode().allowAffinityKey;
if (readIf("CONSTRAINT")) { if (readIf(CONSTRAINT)) {
ifNotExists = readIfNotExists(); ifNotExists = readIfNotExists();
constraintName = readIdentifierWithSchema(schema.getName()); constraintName = readIdentifierWithSchema(schema.getName());
checkSchema(schema); checkSchema(schema);
comment = readCommentIf(); comment = readCommentIf();
allowIndexDefinition = true; allowIndexDefinition = true;
} }
if (readIf("PRIMARY")) { if (readIf(PRIMARY)) {
read("KEY"); read("KEY");
AlterTableAddConstraint command = new AlterTableAddConstraint( AlterTableAddConstraint command = new AlterTableAddConstraint(
session, schema, ifNotExists); session, schema, ifNotExists);
...@@ -6384,7 +6640,7 @@ public class Parser { ...@@ -6384,7 +6640,7 @@ public class Parser {
if (readIf("HASH")) { if (readIf("HASH")) {
command.setPrimaryKeyHash(true); command.setPrimaryKeyHash(true);
} }
read("("); read(OPEN_PAREN);
command.setIndexColumns(parseIndexColumnList()); command.setIndexColumns(parseIndexColumnList());
if (readIf("INDEX")) { if (readIf("INDEX")) {
String indexName = readIdentifierWithSchema(); String indexName = readIdentifierWithSchema();
...@@ -6406,9 +6662,9 @@ public class Parser { ...@@ -6406,9 +6662,9 @@ public class Parser {
command.setComment(comment); command.setComment(comment);
command.setTableName(tableName); command.setTableName(tableName);
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
if (!readIf("(")) { if (!readIf(OPEN_PAREN)) {
command.setIndexName(readUniqueIdentifier()); command.setIndexName(readUniqueIdentifier());
read("("); read(OPEN_PAREN);
} }
command.setIndexColumns(parseIndexColumnList()); command.setIndexColumns(parseIndexColumnList());
// MySQL compatibility // MySQL compatibility
...@@ -6418,24 +6674,24 @@ public class Parser { ...@@ -6418,24 +6674,24 @@ public class Parser {
return command; return command;
} else if (allowAffinityKey && readIfAffinity()) { } else if (allowAffinityKey && readIfAffinity()) {
read("KEY"); read("KEY");
read("("); read(OPEN_PAREN);
CreateIndex command = createAffinityIndex(schema, tableName, parseIndexColumnList()); CreateIndex command = createAffinityIndex(schema, tableName, parseIndexColumnList());
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
return command; return command;
} }
AlterTableAddConstraint command; AlterTableAddConstraint command;
if (readIf("CHECK")) { if (readIf(CHECK)) {
command = new AlterTableAddConstraint(session, schema, ifNotExists); command = new AlterTableAddConstraint(session, schema, ifNotExists);
command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK); command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK);
command.setCheckExpression(readExpression()); command.setCheckExpression(readExpression());
} else if (readIf("UNIQUE")) { } else if (readIf(UNIQUE)) {
readIf("KEY"); readIf("KEY");
readIf("INDEX"); readIf("INDEX");
command = new AlterTableAddConstraint(session, schema, ifNotExists); command = new AlterTableAddConstraint(session, schema, ifNotExists);
command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE); command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE);
if (!readIf("(")) { if (!readIf(OPEN_PAREN)) {
constraintName = readUniqueIdentifier(); constraintName = readUniqueIdentifier();
read("("); read(OPEN_PAREN);
} }
command.setIndexColumns(parseIndexColumnList()); command.setIndexColumns(parseIndexColumnList());
if (readIf("INDEX")) { if (readIf("INDEX")) {
...@@ -6446,11 +6702,11 @@ public class Parser { ...@@ -6446,11 +6702,11 @@ public class Parser {
if (readIf("USING")) { if (readIf("USING")) {
read("BTREE"); read("BTREE");
} }
} else if (readIf("FOREIGN")) { } else if (readIf(FOREIGN)) {
command = new AlterTableAddConstraint(session, schema, ifNotExists); command = new AlterTableAddConstraint(session, schema, ifNotExists);
command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL); command.setType(CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL);
read("KEY"); read("KEY");
read("("); read(OPEN_PAREN);
command.setIndexColumns(parseIndexColumnList()); command.setIndexColumns(parseIndexColumnList());
if (readIf("INDEX")) { if (readIf("INDEX")) {
String indexName = readIdentifierWithSchema(); String indexName = readIdentifierWithSchema();
...@@ -6467,7 +6723,7 @@ public class Parser { ...@@ -6467,7 +6723,7 @@ public class Parser {
if (readIf("NOCHECK")) { if (readIf("NOCHECK")) {
command.setCheckExisting(false); command.setCheckExisting(false);
} else { } else {
readIf("CHECK"); readIf(CHECK);
command.setCheckExisting(true); command.setCheckExisting(true);
} }
command.setTableName(tableName); command.setTableName(tableName);
...@@ -6479,13 +6735,13 @@ public class Parser { ...@@ -6479,13 +6735,13 @@ public class Parser {
private void parseReferences(AlterTableAddConstraint command, private void parseReferences(AlterTableAddConstraint command,
Schema schema, String tableName) { Schema schema, String tableName) {
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
command.setRefTableName(schema, tableName); command.setRefTableName(schema, tableName);
command.setRefIndexColumns(parseIndexColumnList()); command.setRefIndexColumns(parseIndexColumnList());
} else { } else {
String refTableName = readIdentifierWithSchema(schema.getName()); String refTableName = readIdentifierWithSchema(schema.getName());
command.setRefTableName(getSchema(), refTableName); command.setRefTableName(getSchema(), refTableName);
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
command.setRefIndexColumns(parseIndexColumnList()); command.setRefIndexColumns(parseIndexColumnList());
} }
} }
...@@ -6493,7 +6749,7 @@ public class Parser { ...@@ -6493,7 +6749,7 @@ public class Parser {
String indexName = readIdentifierWithSchema(); String indexName = readIdentifierWithSchema();
command.setRefIndex(getSchema().findIndex(session, indexName)); command.setRefIndex(getSchema().findIndex(session, indexName));
} }
while (readIf("ON")) { while (readIf(ON)) {
if (readIf("DELETE")) { if (readIf("DELETE")) {
command.setDeleteAction(parseAction()); command.setDeleteAction(parseAction());
} else { } else {
...@@ -6501,7 +6757,7 @@ public class Parser { ...@@ -6501,7 +6757,7 @@ public class Parser {
command.setUpdateAction(parseAction()); command.setUpdateAction(parseAction());
} }
} }
if (readIf("NOT")) { if (readIf(NOT)) {
read("DEFERRABLE"); read("DEFERRABLE");
} else { } else {
readIf("DEFERRABLE"); readIf("DEFERRABLE");
...@@ -6520,7 +6776,7 @@ public class Parser { ...@@ -6520,7 +6776,7 @@ public class Parser {
command.setIfNotExists(ifNotExists); command.setIfNotExists(ifNotExists);
command.setTableName(tableName); command.setTableName(tableName);
command.setComment(readCommentIf()); command.setComment(readCommentIf());
read("("); read(OPEN_PAREN);
command.setDriver(readString()); command.setDriver(readString());
read(","); read(",");
command.setUrl(readString()); command.setUrl(readString());
...@@ -6535,7 +6791,7 @@ public class Parser { ...@@ -6535,7 +6791,7 @@ public class Parser {
originalTable = readString(); originalTable = readString();
} }
command.setOriginalTable(originalTable); command.setOriginalTable(originalTable);
read(")"); read(CLOSE_PAREN);
if (readIf("EMIT")) { if (readIf("EMIT")) {
read("UPDATES"); read("UPDATES");
command.setEmitUpdates(true); command.setEmitUpdates(true);
...@@ -6563,8 +6819,8 @@ public class Parser { ...@@ -6563,8 +6819,8 @@ public class Parser {
command.setIfNotExists(ifNotExists); command.setIfNotExists(ifNotExists);
command.setTableName(tableName); command.setTableName(tableName);
command.setComment(readCommentIf()); command.setComment(readCommentIf());
if (readIf("(")) { if (readIf(OPEN_PAREN)) {
if (!readIf(")")) { if (!readIf(CLOSE_PAREN)) {
do { do {
parseTableColumnDefinition(command, schema, tableName); parseTableColumnDefinition(command, schema, tableName);
} while (readIfMore(false)); } while (readIfMore(false));
...@@ -6572,13 +6828,13 @@ public class Parser { ...@@ -6572,13 +6828,13 @@ public class Parser {
} }
// Allows "COMMENT='comment'" in DDL statements (MySQL syntax) // Allows "COMMENT='comment'" in DDL statements (MySQL syntax)
if (readIf("COMMENT")) { if (readIf("COMMENT")) {
if (readIf("=")) { if (readIf(EQUAL)) {
// read the complete string comment, but nothing with it for now // read the complete string comment, but nothing with it for now
readString(); readString();
} }
} }
if (readIf("ENGINE")) { if (readIf("ENGINE")) {
if (readIf("=")) { if (readIf(EQUAL)) {
// map MySQL engine types onto H2 behavior // map MySQL engine types onto H2 behavior
String tableEngine = readUniqueIdentifier(); String tableEngine = readUniqueIdentifier();
if ("InnoDb".equalsIgnoreCase(tableEngine)) { if ("InnoDb".equalsIgnoreCase(tableEngine)) {
...@@ -6590,12 +6846,12 @@ public class Parser { ...@@ -6590,12 +6846,12 @@ public class Parser {
command.setTableEngine(readUniqueIdentifier()); command.setTableEngine(readUniqueIdentifier());
} }
} }
if (readIf("WITH")) { if (readIf(WITH)) {
command.setTableEngineParams(readTableEngineParams()); command.setTableEngineParams(readTableEngineParams());
} }
// MySQL compatibility // MySQL compatibility
if (readIf("AUTO_INCREMENT")) { if (readIf("AUTO_INCREMENT")) {
read("="); read(EQUAL);
if (currentTokenType != VALUE || if (currentTokenType != VALUE ||
currentValue.getType() != Value.INT) { currentValue.getType() != Value.INT) {
throw DbException.getSyntaxError(sqlCommand, parseIndex, throw DbException.getSyntaxError(sqlCommand, parseIndex,
...@@ -6605,13 +6861,13 @@ public class Parser { ...@@ -6605,13 +6861,13 @@ public class Parser {
} }
readIf("DEFAULT"); readIf("DEFAULT");
if (readIf("CHARSET")) { if (readIf("CHARSET")) {
read("="); read(EQUAL);
if (!readIf("UTF8")) { if (!readIf("UTF8")) {
read("UTF8MB4"); read("UTF8MB4");
} }
} }
if (temp) { if (temp) {
if (readIf("ON")) { if (readIf(ON)) {
read("COMMIT"); read("COMMIT");
if (readIf("DROP")) { if (readIf("DROP")) {
command.setOnCommitDrop(); command.setOnCommitDrop();
...@@ -6619,7 +6875,7 @@ public class Parser { ...@@ -6619,7 +6875,7 @@ public class Parser {
read("ROWS"); read("ROWS");
command.setOnCommitTruncate(); command.setOnCommitTruncate();
} }
} else if (readIf("NOT")) { } else if (readIf(NOT)) {
if (readIf("PERSISTENT")) { if (readIf("PERSISTENT")) {
command.setPersistData(false); command.setPersistData(false);
} else { } else {
...@@ -6629,7 +6885,7 @@ public class Parser { ...@@ -6629,7 +6885,7 @@ public class Parser {
if (readIf("TRANSACTIONAL")) { if (readIf("TRANSACTIONAL")) {
command.setTransactional(true); command.setTransactional(true);
} }
} else if (!persistIndexes && readIf("NOT")) { } else if (!persistIndexes && readIf(NOT)) {
read("PERSISTENT"); read("PERSISTENT");
command.setPersistData(false); command.setPersistData(false);
} }
...@@ -6641,14 +6897,14 @@ public class Parser { ...@@ -6641,14 +6897,14 @@ public class Parser {
command.setSortedInsertMode(true); command.setSortedInsertMode(true);
} }
command.setQuery(parseSelect()); command.setQuery(parseSelect());
if (readIf("WITH")) { if (readIf(WITH)) {
command.setWithNoData(readIf("NO")); command.setWithNoData(readIf("NO"));
read("DATA"); read("DATA");
} }
} }
// for MySQL compatibility // for MySQL compatibility
if (readIf("ROW_FORMAT")) { if (readIf("ROW_FORMAT")) {
if (readIf("=")) { if (readIf(EQUAL)) {
readColumnIdentifier(); readColumnIdentifier();
} }
} }
...@@ -6676,13 +6932,13 @@ public class Parser { ...@@ -6676,13 +6932,13 @@ public class Parser {
} }
command.addColumn(column); command.addColumn(column);
String constraintName = null; String constraintName = null;
if (readIf("CONSTRAINT")) { if (readIf(CONSTRAINT)) {
constraintName = readColumnIdentifier(); constraintName = readColumnIdentifier();
} }
// For compatibility with Apache Ignite. // For compatibility with Apache Ignite.
boolean allowAffinityKey = database.getMode().allowAffinityKey; boolean allowAffinityKey = database.getMode().allowAffinityKey;
boolean affinity = allowAffinityKey && readIfAffinity(); boolean affinity = allowAffinityKey && readIfAffinity();
if (readIf("PRIMARY")) { if (readIf(PRIMARY)) {
read("KEY"); read("KEY");
boolean hash = readIf("HASH"); boolean hash = readIf("HASH");
IndexColumn[] cols = { new IndexColumn() }; IndexColumn[] cols = { new IndexColumn() };
...@@ -6708,7 +6964,7 @@ public class Parser { ...@@ -6708,7 +6964,7 @@ public class Parser {
cols[0].columnName = column.getName(); cols[0].columnName = column.getName();
CreateIndex idx = createAffinityIndex(schema, tableName, cols); CreateIndex idx = createAffinityIndex(schema, tableName, cols);
command.addConstraintCommand(idx); command.addConstraintCommand(idx);
} else if (readIf("UNIQUE")) { } else if (readIf(UNIQUE)) {
AlterTableAddConstraint unique = new AlterTableAddConstraint( AlterTableAddConstraint unique = new AlterTableAddConstraint(
session, schema, false); session, schema, false);
unique.setConstraintName(constraintName); unique.setConstraintName(constraintName);
...@@ -6722,7 +6978,7 @@ public class Parser { ...@@ -6722,7 +6978,7 @@ public class Parser {
if (NullConstraintType.NULL_IS_NOT_ALLOWED == parseNotNullConstraint()) { if (NullConstraintType.NULL_IS_NOT_ALLOWED == parseNotNullConstraint()) {
column.setNullable(false); column.setNullable(false);
} }
if (readIf("CHECK")) { if (readIf(CHECK)) {
Expression expr = readExpression(); Expression expr = readExpression();
column.addCheckConstraint(session, expr); column.addCheckConstraint(session, expr);
} }
...@@ -6750,12 +7006,12 @@ public class Parser { ...@@ -6750,12 +7006,12 @@ public class Parser {
private NullConstraintType parseNotNullConstraint() { private NullConstraintType parseNotNullConstraint() {
NullConstraintType nullConstraint = NullConstraintType.NO_NULL_CONSTRAINT_FOUND; NullConstraintType nullConstraint = NullConstraintType.NO_NULL_CONSTRAINT_FOUND;
if (isToken("NOT") || isToken("NULL")) { if (isToken(NOT) || isToken(NULL)) {
if (readIf("NOT")) { if (readIf(NOT)) {
read("NULL"); read(NULL);
nullConstraint = NullConstraintType.NULL_IS_NOT_ALLOWED; nullConstraint = NullConstraintType.NULL_IS_NOT_ALLOWED;
} else { } else {
read("NULL"); read(NULL);
nullConstraint = NullConstraintType.NULL_IS_ALLOWED; nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
} }
if (database.getMode().getEnum() == ModeEnum.Oracle) { if (database.getMode().getEnum() == ModeEnum.Oracle) {
...@@ -6784,7 +7040,7 @@ public class Parser { ...@@ -6784,7 +7040,7 @@ public class Parser {
boolean ifNotExists = readIfNotExists(); boolean ifNotExists = readIfNotExists();
String name = readIdentifierWithSchema(); String name = readIdentifierWithSchema();
Schema synonymSchema = getSchema(); Schema synonymSchema = getSchema();
read("FOR"); read(FOR);
String tableName = readIdentifierWithSchema(); String tableName = readIdentifierWithSchema();
Schema targetSchema = getSchema(); Schema targetSchema = getSchema();
......
...@@ -18,24 +18,199 @@ public class ParserUtil { ...@@ -18,24 +18,199 @@ public class ParserUtil {
public static final int IDENTIFIER = 2; public static final int IDENTIFIER = 2;
/** /**
* The token "null". * The token "ALL".
*/ */
public static final int NULL = 3; public static final int ALL = IDENTIFIER + 1;
/** /**
* The token "true". * The token "CHECK".
*/ */
public static final int TRUE = 4; public static final int CHECK = ALL + 1;
/** /**
* The token "false". * The token "CONSTRAINT".
*/ */
public static final int FALSE = 5; public static final int CONSTRAINT = CHECK + 1;
/** /**
* The token "rownum". * The token "CROSS".
*/ */
public static final int ROWNUM = 6; public static final int CROSS = CONSTRAINT + 1;
/**
* The token "CURRENT_DATE".
*/
public static final int CURRENT_DATE = CROSS + 1;
/**
* The token "CURRENT_TIME".
*/
public static final int CURRENT_TIME = CURRENT_DATE + 1;
/**
* The token "CURRENT_TIMESTAMP".
*/
public static final int CURRENT_TIMESTAMP = CURRENT_TIME + 1;
/**
* The token "DISTINCT".
*/
public static final int DISTINCT = CURRENT_TIMESTAMP + 1;
/**
* The token "EXCEPT".
*/
public static final int EXCEPT = DISTINCT + 1;
/**
* The token "EXISTS".
*/
public static final int EXISTS = EXCEPT + 1;
/**
* The token "FALSE".
*/
public static final int FALSE = EXISTS + 1;
/**
* The token "FETCH".
*/
public static final int FETCH = FALSE + 1;
/**
* The token "FOR".
*/
public static final int FOR = FETCH + 1;
/**
* The token "FOREIGN".
*/
public static final int FOREIGN = FOR + 1;
/**
* The token "FROM".
*/
public static final int FROM = FOREIGN + 1;
/**
* The token "FULL".
*/
public static final int FULL = FROM + 1;
/**
* The token "GROUP".
*/
public static final int GROUP = FULL + 1;
/**
* The token "HAVING".
*/
public static final int HAVING = GROUP + 1;
/**
* The token "INNER".
*/
public static final int INNER = HAVING + 1;
/**
* The token "INTERSECT".
*/
public static final int INTERSECT = INNER + 1;
/**
* The token "IS".
*/
public static final int IS = INTERSECT + 1;
/**
* The token "JOIN".
*/
public static final int JOIN = IS + 1;
/**
* The token "LIKE".
*/
public static final int LIKE = JOIN + 1;
/**
* The token "LIMIT".
*/
public static final int LIMIT = LIKE + 1;
/**
* The token "MINUS".
*/
public static final int MINUS = LIMIT + 1;
/**
* The token "NATURAL".
*/
public static final int NATURAL = MINUS + 1;
/**
* The token "NOT".
*/
public static final int NOT = NATURAL + 1;
/**
* The token "NULL".
*/
public static final int NULL = NOT + 1;
/**
* The token "OFFSET".
*/
public static final int OFFSET = NULL + 1;
/**
* The token "ON".
*/
public static final int ON = OFFSET + 1;
/**
* The token "ORDER".
*/
public static final int ORDER = ON + 1;
/**
* The token "PRIMARY".
*/
public static final int PRIMARY = ORDER + 1;
/**
* The token "ROWNUM".
*/
public static final int ROWNUM = PRIMARY + 1;
/**
* The token "SELECT".
*/
public static final int SELECT = ROWNUM + 1;
/**
* The token "TRUE".
*/
public static final int TRUE = SELECT + 1;
/**
* The token "UNION".
*/
public static final int UNION = TRUE + 1;
/**
* The token "UNIQUE".
*/
public static final int UNIQUE = UNION + 1;
/**
* The token "WHERE".
*/
public static final int WHERE = UNIQUE + 1;
/**
* The token "WITH".
*/
public static final int WITH = WHERE + 1;
private ParserUtil() { private ParserUtil() {
// utility class // utility class
...@@ -95,14 +270,14 @@ public class ParserUtil { ...@@ -95,14 +270,14 @@ public class ParserUtil {
*/ */
switch (s.charAt(0)) { switch (s.charAt(0)) {
case 'A': case 'A':
return getKeywordOrIdentifier(s, "ALL", KEYWORD); return getKeywordOrIdentifier(s, "ALL", ALL);
case 'C': case 'C':
if ("CHECK".equals(s)) { if ("CHECK".equals(s)) {
return KEYWORD; return CHECK;
} else if ("CONSTRAINT".equals(s)) { } else if ("CONSTRAINT".equals(s)) {
return KEYWORD; return CONSTRAINT;
} else if ("CROSS".equals(s)) { } else if ("CROSS".equals(s)) {
return KEYWORD; return CROSS;
} }
if (additionalKeywords) { if (additionalKeywords) {
if ("CURRENT_DATE".equals(s) || "CURRENT_TIME".equals(s) || "CURRENT_TIMESTAMP".equals(s)) { if ("CURRENT_DATE".equals(s) || "CURRENT_TIME".equals(s) || "CURRENT_TIMESTAMP".equals(s)) {
...@@ -111,32 +286,36 @@ public class ParserUtil { ...@@ -111,32 +286,36 @@ public class ParserUtil {
} }
return IDENTIFIER; return IDENTIFIER;
case 'D': case 'D':
return getKeywordOrIdentifier(s, "DISTINCT", KEYWORD); return getKeywordOrIdentifier(s, "DISTINCT", DISTINCT);
case 'E': case 'E':
if ("EXCEPT".equals(s)) { if ("EXCEPT".equals(s)) {
return KEYWORD; return EXCEPT;
} }
return getKeywordOrIdentifier(s, "EXISTS", KEYWORD); return getKeywordOrIdentifier(s, "EXISTS", EXISTS);
case 'F': case 'F':
if ("FETCH".equals(s)) { if ("FETCH".equals(s)) {
return KEYWORD; return FETCH;
} else if ("FROM".equals(s)) { } else if ("FROM".equals(s)) {
return KEYWORD; return FROM;
} else if ("FOR".equals(s)) { } else if ("FOR".equals(s)) {
return KEYWORD; return FOR;
} else if ("FOREIGN".equals(s)) { } else if ("FOREIGN".equals(s)) {
return KEYWORD; return FOREIGN;
} else if ("FULL".equals(s)) { } else if ("FULL".equals(s)) {
return KEYWORD; return FULL;
} }
return getKeywordOrIdentifier(s, "FALSE", FALSE); return getKeywordOrIdentifier(s, "FALSE", FALSE);
case 'G': case 'G':
return getKeywordOrIdentifier(s, "GROUP", KEYWORD); return getKeywordOrIdentifier(s, "GROUP", GROUP);
case 'H': case 'H':
return getKeywordOrIdentifier(s, "HAVING", KEYWORD); return getKeywordOrIdentifier(s, "HAVING", HAVING);
case 'I': case 'I':
if ("INNER".equals(s) || "INTERSECT".equals(s) || "IS".equals(s)) { if ("INNER".equals(s)) {
return KEYWORD; return INNER;
} else if ("INTERSECT".equals(s)) {
return INTERSECT;
} else if ("IS".equals(s)) {
return IS;
} }
if (additionalKeywords) { if (additionalKeywords) {
if ("INTERSECTS".equals(s)) { if ("INTERSECTS".equals(s)) {
...@@ -145,10 +324,12 @@ public class ParserUtil { ...@@ -145,10 +324,12 @@ public class ParserUtil {
} }
return IDENTIFIER; return IDENTIFIER;
case 'J': case 'J':
return getKeywordOrIdentifier(s, "JOIN", KEYWORD); return getKeywordOrIdentifier(s, "JOIN", JOIN);
case 'L': case 'L':
if ("LIMIT".equals(s) || "LIKE".equals(s)) { if ("LIMIT".equals(s)) {
return KEYWORD; return LIMIT;
} else if ("LIKE".equals(s)) {
return LIKE;
} }
if (additionalKeywords) { if (additionalKeywords) {
if ("LOCALTIME".equals(s) || "LOCALTIMESTAMP".equals(s)) { if ("LOCALTIME".equals(s) || "LOCALTIMESTAMP".equals(s)) {
...@@ -157,28 +338,28 @@ public class ParserUtil { ...@@ -157,28 +338,28 @@ public class ParserUtil {
} }
return IDENTIFIER; return IDENTIFIER;
case 'M': case 'M':
return getKeywordOrIdentifier(s, "MINUS", KEYWORD); return getKeywordOrIdentifier(s, "MINUS", MINUS);
case 'N': case 'N':
if ("NOT".equals(s)) { if ("NOT".equals(s)) {
return KEYWORD; return NOT;
} else if ("NATURAL".equals(s)) { } else if ("NATURAL".equals(s)) {
return KEYWORD; return NATURAL;
} }
return getKeywordOrIdentifier(s, "NULL", NULL); return getKeywordOrIdentifier(s, "NULL", NULL);
case 'O': case 'O':
if ("OFFSET".equals(s)) { if ("OFFSET".equals(s)) {
return KEYWORD; return OFFSET;
} else if ("ON".equals(s)) { } else if ("ON".equals(s)) {
return KEYWORD; return ON;
} }
return getKeywordOrIdentifier(s, "ORDER", KEYWORD); return getKeywordOrIdentifier(s, "ORDER", ORDER);
case 'P': case 'P':
return getKeywordOrIdentifier(s, "PRIMARY", KEYWORD); return getKeywordOrIdentifier(s, "PRIMARY", PRIMARY);
case 'R': case 'R':
return getKeywordOrIdentifier(s, "ROWNUM", ROWNUM); return getKeywordOrIdentifier(s, "ROWNUM", ROWNUM);
case 'S': case 'S':
if ("SELECT".equals(s)) { if ("SELECT".equals(s)) {
return KEYWORD; return SELECT;
} }
if (additionalKeywords) { if (additionalKeywords) {
if ("SYSDATE".equals(s) || "SYSTIME".equals(s) || "SYSTIMESTAMP".equals(s)) { if ("SYSDATE".equals(s) || "SYSTIME".equals(s) || "SYSTIMESTAMP".equals(s)) {
...@@ -198,14 +379,14 @@ public class ParserUtil { ...@@ -198,14 +379,14 @@ public class ParserUtil {
return IDENTIFIER; return IDENTIFIER;
case 'U': case 'U':
if ("UNIQUE".equals(s)) { if ("UNIQUE".equals(s)) {
return KEYWORD; return UNIQUE;
} }
return getKeywordOrIdentifier(s, "UNION", KEYWORD); return getKeywordOrIdentifier(s, "UNION", UNION);
case 'W': case 'W':
if ("WITH".equals(s)) { if ("WITH".equals(s)) {
return KEYWORD; return WITH;
} }
return getKeywordOrIdentifier(s, "WHERE", KEYWORD); return getKeywordOrIdentifier(s, "WHERE", WHERE);
default: default:
return IDENTIFIER; return IDENTIFIER;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论