提交 76e61e71 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add TestKeywords and missing keywords

上级 f69172a5
......@@ -475,13 +475,14 @@ There is a list of keywords that can't be used as identifiers (table names, colu
unless they are quoted (surrounded with double quotes). The list is currently:
</p><p>
<code>
ALL, ARRAY, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME,
CURRENT_TIMESTAMP, DISTINCT, EXCEPT, EXISTS, FALSE, FETCH, FOR,
FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS,
INTERVAL, IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP,
MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROW,
ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE,
UNION, UNIQUE, WHERE, WINDOW, WITH
ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE,
CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT,
EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING,
IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES,
WHERE, WINDOW, WITH
</code>
</p><p>
Certain words of this list are keywords because they are functions that can be used without '()',
......
......@@ -10,12 +10,14 @@ package org.h2.command;
import static org.h2.util.ParserUtil.ALL;
import static org.h2.util.ParserUtil.ARRAY;
import static org.h2.util.ParserUtil.CASE;
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.CURRENT_DATE;
import static org.h2.util.ParserUtil.CURRENT_TIME;
import static org.h2.util.ParserUtil.CURRENT_TIMESTAMP;
import static org.h2.util.ParserUtil.CURRENT_USER;
import static org.h2.util.ParserUtil.DISTINCT;
import static org.h2.util.ParserUtil.EXCEPT;
import static org.h2.util.ParserUtil.EXISTS;
......@@ -28,6 +30,7 @@ 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.IF;
import static org.h2.util.ParserUtil.INNER;
import static org.h2.util.ParserUtil.INTERSECT;
import static org.h2.util.ParserUtil.INTERSECTS;
......@@ -52,6 +55,7 @@ import static org.h2.util.ParserUtil.SELECT;
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.VALUES;
import static org.h2.util.ParserUtil.WHERE;
import static org.h2.util.ParserUtil.WINDOW;
import static org.h2.util.ParserUtil.WITH;
......@@ -424,6 +428,8 @@ public class Parser {
"ALL",
// ARRAY
"ARRAY",
// CASE
"CASE",
// CHECK
"CHECK",
// CONSTRAINT
......@@ -436,6 +442,8 @@ public class Parser {
"CURRENT_TIME",
// CURRENT_TIMESTAMP
"CURRENT_TIMESTAMP",
// CURRENT_USER
"CURRENT_USER",
// DISTINCT
"DISTINCT",
// EXCEPT
......@@ -458,6 +466,8 @@ public class Parser {
"GROUP",
// HAVING
"HAVING",
// IF
"IF",
// INNER
"INNER",
// INTERSECT
......@@ -506,6 +516,8 @@ public class Parser {
"UNION",
// UNIQUE
"UNIQUE",
// VALUES
"VALUES",
// WHERE
"WHERE",
// WINDOW
......@@ -735,6 +747,10 @@ public class Parser {
case SELECT:
c = parseSelect();
break;
case VALUES:
read();
c = parseValues();
break;
case WITH:
read();
c = parseWithStatementOrQuery();
......@@ -867,11 +883,6 @@ public class Parser {
c = parseUse();
}
break;
case 'v':
case 'V':
if (readIf("VALUES")) {
c = parseValues();
}
}
}
if (c == null) {
......@@ -1434,7 +1445,7 @@ public class Parser {
private Prepared parseMerge() {
int start = lastParseIndex;
read("INTO");
List<String> excludeIdentifiers = Arrays.asList("USING", "KEY", "VALUES");
List<String> excludeIdentifiers = Arrays.asList("USING", "KEY");
TableFilter targetTableFilter = readSimpleTableFilter(0, excludeIdentifiers);
if (readIf("USING")) {
return parseMergeUsing(targetTableFilter, start);
......@@ -1457,7 +1468,7 @@ public class Parser {
Column[] keys = parseColumnList(table);
command.setKeys(keys);
}
if (readIf("VALUES")) {
if (readIf(VALUES)) {
do {
read(OPEN_PAREN);
command.addRow(parseValuesForInsert());
......@@ -1644,10 +1655,10 @@ public class Parser {
command.setSortedInsertMode(true);
}
if (readIf("DEFAULT")) {
read("VALUES");
read(VALUES);
Expression[] expr = {};
command.addRow(expr);
} else if (readIf("VALUES")) {
} else if (readIf(VALUES)) {
read(OPEN_PAREN);
do {
command.addRow(parseValuesForInsert());
......@@ -1690,7 +1701,7 @@ public class Parser {
Column[] columns = parseColumnList(table);
command.setColumns(columns);
}
if (readIf("VALUES")) {
if (readIf(VALUES)) {
do {
read(OPEN_PAREN);
command.addRow(parseValuesForInsert());
......@@ -1748,7 +1759,7 @@ public class Parser {
}
return top;
}
} else if (readIf("VALUES")) {
} else if (readIf(VALUES)) {
table = parseValuesTable(0).getTable();
} else {
String tableName = readIdentifierWithSchema(null);
......@@ -1927,7 +1938,7 @@ public class Parser {
}
private boolean readIfExists(boolean ifExists) {
if (readIf("IF")) {
if (readIf(IF)) {
read(EXISTS);
ifExists = true;
}
......@@ -3751,8 +3762,8 @@ public class Parser {
break;
case IDENTIFIER:
String name = currentToken;
read();
if (currentTokenQuoted) {
read();
if (readIf(OPEN_PAREN)) {
r = readFunction(null, name);
} else if (readIf(DOT)) {
......@@ -3761,14 +3772,8 @@ public class Parser {
r = new ExpressionColumn(database, null, null, name);
}
} else {
read();
if (readIf(DOT)) {
r = readTermObjectDot(name);
} else if (equalsToken("CASE", name)) {
// CASE must be processed before (,
// otherwise CASE(3) would be a function call, which it is
// not
r = readCase();
} else if (readIf(OPEN_PAREN)) {
r = readFunction(null, name);
} else {
......@@ -3879,6 +3884,14 @@ public class Parser {
r = ValueExpression.get(currentValue);
read();
break;
case VALUES:
read();
r = readKeywordFunction("VALUES");
break;
case CASE:
read();
r = readCase();
break;
case CURRENT_DATE:
read();
r = readKeywordFunction("CURRENT_DATE");
......@@ -3891,6 +3904,10 @@ public class Parser {
read();
r = readKeywordFunction("CURRENT_TIMESTAMP");
break;
case CURRENT_USER:
read();
r = readKeywordFunction("USER");
break;
case LOCALTIME:
read();
r = readKeywordFunction("LOCALTIME");
......@@ -3946,9 +3963,7 @@ public class Parser {
}
switch (ch) {
case 'C':
if (equalsToken("CURRENT_USER", name)) {
return readFunctionWithoutParameters("USER");
} else if (database.getMode().getEnum() == ModeEnum.DB2 && equalsToken("CURRENT", name)) {
if (database.getMode().getEnum() == ModeEnum.DB2 && equalsToken("CURRENT", name)) {
return parseDB2SpecialRegisters(name);
}
break;
......@@ -4134,13 +4149,13 @@ public class Parser {
private Expression readCase() {
if (readIf("END")) {
readIf("CASE");
readIf(CASE);
return ValueExpression.getNull();
}
if (readIf("ELSE")) {
Expression elsePart = readExpression().optimize(session);
read("END");
readIf("CASE");
readIf(CASE);
return elsePart;
}
int i;
......@@ -4157,13 +4172,13 @@ public class Parser {
} else {
Expression expr = readExpression();
if (readIf("END")) {
readIf("CASE");
readIf(CASE);
return ValueExpression.getNull();
}
if (readIf("ELSE")) {
Expression elsePart = readExpression().optimize(session);
read("END");
readIf("CASE");
readIf(CASE);
return elsePart;
}
function = Function.getFunction(database, "CASE");
......@@ -5879,7 +5894,7 @@ public class Parser {
}
private boolean readIfNotExists() {
if (readIf("IF")) {
if (readIf(IF)) {
read(NOT);
read(EXISTS);
return true;
......
......@@ -1547,13 +1547,14 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* </pre>
* The complete list of keywords (including SQL-2003 keywords) is:
* <pre>
* ALL, ARRAY, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME,
* CURRENT_TIMESTAMP, DISTINCT, EXCEPT, EXISTS, FALSE, FETCH, FOR,
* FOREIGN, FROM, FULL, GROUP, HAVING, INNER, INTERSECT, INTERSECTS,
* INTERVAL, IS, JOIN, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP,
* MINUS, NATURAL, NOT, NULL, OFFSET, ON, ORDER, PRIMARY, ROW,
* ROWNUM, SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE,
* UNION, UNIQUE, WHERE, WINDOW, WITH
* ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE,
* CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT,
* EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING,
* IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE,
* LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL,
* OFFSET, ON, ORDER, PRIMARY, ROW, ROWNUM, SELECT, SYSDATE,
* SYSTIME, SYSTIMESTAMP, TODAY, TOP, TRUE, UNION, UNIQUE, VALUES,
* WHERE, WINDOW, WITH
* </pre>
*
* @return a list of additional the keywords
......@@ -1561,7 +1562,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements
@Override
public String getSQLKeywords() {
debugCodeCall("getSQLKeywords");
return "INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP";
return "IF,INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP";
}
/**
......
......@@ -27,10 +27,15 @@ public class ParserUtil {
*/
public static final int ARRAY = ALL + 1;
/**
* The token "CASE".
*/
public static final int CASE = ARRAY + 1;
/**
* The token "CHECK".
*/
public static final int CHECK = ARRAY + 1;
public static final int CHECK = CASE + 1;
/**
* The token "CONSTRAINT".
......@@ -57,10 +62,15 @@ public class ParserUtil {
*/
public static final int CURRENT_TIMESTAMP = CURRENT_TIME + 1;
/**
* The token "CURRENT_USER".
*/
public static final int CURRENT_USER = CURRENT_TIMESTAMP + 1;
/**
* The token "DISTINCT".
*/
public static final int DISTINCT = CURRENT_TIMESTAMP + 1;
public static final int DISTINCT = CURRENT_USER + 1;
/**
* The token "EXCEPT".
......@@ -112,10 +122,15 @@ public class ParserUtil {
*/
public static final int HAVING = GROUP + 1;
/**
* The token "IF".
*/
public static final int IF = HAVING + 1;
/**
* The token "INNER".
*/
public static final int INNER = HAVING + 1;
public static final int INNER = IF + 1;
/**
* The token "INTERSECT".
......@@ -232,10 +247,15 @@ public class ParserUtil {
*/
public static final int UNIQUE = UNION + 1;
/**
* The token "VALUES".
*/
public static final int VALUES = UNIQUE + 1;
/**
* The token "WHERE".
*/
public static final int WHERE = UNIQUE + 1;
public static final int WHERE = VALUES + 1;
/**
* The token "WINDOW".
......@@ -337,7 +357,9 @@ public class ParserUtil {
}
return IDENTIFIER;
case 'C':
if (eq("CHECK", s, ignoreCase, start, end)) {
if (eq("CASE", s, ignoreCase, start, end)) {
return CASE;
} else if (eq("CHECK", s, ignoreCase, start, end)) {
return CHECK;
} else if (eq("CONSTRAINT", s, ignoreCase, start, end)) {
return CONSTRAINT;
......@@ -349,6 +371,8 @@ public class ParserUtil {
return CURRENT_TIME;
} else if (eq("CURRENT_TIMESTAMP", s, ignoreCase, start, end)) {
return CURRENT_TIMESTAMP;
} else if (eq("CURRENT_USER", s, ignoreCase, start, end)) {
return CURRENT_USER;
}
return IDENTIFIER;
case 'D':
......@@ -389,7 +413,9 @@ public class ParserUtil {
}
return IDENTIFIER;
case 'I':
if (eq("INNER", s, ignoreCase, start, end)) {
if (eq("IF", s, ignoreCase, start, end)) {
return IF;
} else if (eq("INNER", s, ignoreCase, start, end)) {
return INNER;
} else if (eq("INTERSECT", s, ignoreCase, start, end)) {
return INTERSECT;
......@@ -480,6 +506,11 @@ public class ParserUtil {
return UNION;
}
return IDENTIFIER;
case 'V':
if (eq("VALUES", s, ignoreCase, start, end)) {
return VALUES;
}
return IDENTIFIER;
case 'W':
if (eq("WHERE", s, ignoreCase, start, end)) {
return WHERE;
......
......@@ -196,6 +196,7 @@ import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestIntPerfectHash;
import org.h2.test.unit.TestInterval;
import org.h2.test.unit.TestJmx;
import org.h2.test.unit.TestKeywords;
import org.h2.test.unit.TestLocalResultFactory;
import org.h2.test.unit.TestLocale;
import org.h2.test.unit.TestMathUtils;
......@@ -973,6 +974,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
addTest(new TestIntArray());
addTest(new TestIntIntHashMap());
addTest(new TestIntPerfectHash());
addTest(new TestKeywords());
addTest(new TestMathUtils());
addTest(new TestMemoryUnmapper());
addTest(new TestMode());
......
......@@ -463,7 +463,7 @@ public class TestMetaData extends TestDb {
assertEquals("schema", meta.getSchemaTerm());
assertEquals("\\", meta.getSearchStringEscape());
assertEquals("INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP",
assertEquals("IF,INTERSECTS,LIMIT,MINUS,OFFSET,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP",
meta.getSQLKeywords());
assertTrue(meta.getURL().startsWith("jdbc:h2:"));
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashSet;
import org.h2.command.Parser;
import org.h2.test.TestBase;
import org.h2.util.ParserUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* Tests keywords.
*/
public class TestKeywords extends TestBase {
/**
* Run just this test.
*
* @param a
* ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() throws Exception {
final HashSet<String> set = new HashSet<>();
ClassReader r = new ClassReader(Parser.class.getResourceAsStream("Parser.class"));
r.accept(new ClassVisitor(Opcodes.ASM6) {
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
add(set, value);
return null;
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
return new MethodVisitor(Opcodes.ASM6) {
@Override
public void visitLdcInsn(Object value) {
add(set, value);
}
};
}
void add(HashSet<String> set, Object value) {
if (!(value instanceof String)) {
return;
}
String s = (String) value;
int l = s.length();
if (l == 0 || ParserUtil.getSaveTokenType(s, false, 0, l, true) != ParserUtil.IDENTIFIER) {
return;
}
for (int i = 0; i < l; i++) {
char ch = s.charAt(i);
if ((ch < 'A' || ch > 'Z') && ch != '_') {
return;
}
}
set.add(s);
}
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
try (Connection conn = DriverManager.getConnection("jdbc:h2:mem:keywords")) {
Statement stat = conn.createStatement();
for (String s : set) {
// _ROWID_ is a special virtual column
String column = s.equals("_ROWID_") ? "C" : s;
try {
stat.execute("CREATE TABLE " + s + '(' + column + " INT)");
stat.execute("INSERT INTO " + s + '(' + column + ") VALUES (10)");
try (ResultSet rs = stat.executeQuery("SELECT " + column + " FROM " + s)) {
assertTrue(rs.next());
assertEquals(10, rs.getInt(1));
assertFalse(rs.next());
}
} catch (Throwable t) {
throw new AssertionError(s + " cannot be used as identifier.", t);
}
}
}
}
}
......@@ -163,9 +163,6 @@ public class Build extends BuildBase {
downloadUsingMaven("ext/org.jacoco.report-0.8.0.jar",
"org.jacoco", "org.jacoco.report", "0.8.0",
"1bcab2a451f5a382bc674857c8f3f6d3fa52151d");
downloadUsingMaven("ext/asm-6.1.jar",
"org.ow2.asm", "asm", "6.1",
"94a0d17ba8eb24833cd54253ace9b053786a9571");
downloadUsingMaven("ext/asm-commons-6.1.jar",
"org.ow2.asm", "asm-commons", "6.1",
"8a8d242d7ce00fc937a245fae5b65763d13f7cd1");
......@@ -272,6 +269,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/org.osgi.core-4.2.0.jar" +
File.pathSeparator + "ext/org.osgi.enterprise-4.2.0.jar" +
File.pathSeparator + "ext/jts-core-1.15.0.jar" +
File.pathSeparator + "ext/asm-6.1.jar" +
File.pathSeparator + javaToolsJar;
FileList files;
if (clientOnly) {
......@@ -386,6 +384,9 @@ public class Build extends BuildBase {
downloadOrVerify("ext/junit-4.12.jar",
"junit", "junit", "4.12",
"2973d150c0dc1fefe998f834810d68f278ea58ec", offline);
downloadUsingMaven("ext/asm-6.1.jar",
"org.ow2.asm", "asm", "6.1",
"94a0d17ba8eb24833cd54253ace9b053786a9571");
}
private void downloadOrVerify(String target, String group, String artifact,
......@@ -962,6 +963,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/jts-core-1.15.0.jar" +
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" +
File.pathSeparator + "ext/asm-6.1.jar" +
File.pathSeparator + javaToolsJar;
int version = getJavaVersion();
if (version >= 9) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论