Unverified 提交 6801c1e5 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1768 from katzyn/misc

Add more context-sensitive keywords
...@@ -490,8 +490,14 @@ The following tokens are keywords in H2: ...@@ -490,8 +490,14 @@ The following tokens are keywords in H2:
<tbody> <tbody>
<tr><td>ALL</td> <tr><td>ALL</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>AND</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>ARRAY</td> <tr><td>ARRAY</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>AS</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>BETWEEN</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>NR</td><td>+</td></tr>
<tr><td>CASE</td> <tr><td>CASE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>CHECK</td> <tr><td>CHECK</td>
...@@ -518,6 +524,8 @@ The following tokens are keywords in H2: ...@@ -518,6 +524,8 @@ The following tokens are keywords in H2:
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FETCH</td> <tr><td>FETCH</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FILTER</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td></td><td></td></tr>
<tr><td>FOR</td> <tr><td>FOR</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>FOREIGN</td> <tr><td>FOREIGN</td>
...@@ -532,6 +540,10 @@ The following tokens are keywords in H2: ...@@ -532,6 +540,10 @@ The following tokens are keywords in H2:
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>IF</td> <tr><td>IF</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>ILIKE</td>
<td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>IN</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>INNER</td> <tr><td>INNER</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>INTERSECT</td> <tr><td>INTERSECT</td>
...@@ -544,10 +556,12 @@ The following tokens are keywords in H2: ...@@ -544,10 +556,12 @@ The following tokens are keywords in H2:
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>JOIN</td> <tr><td>JOIN</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>LEFT</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>LIKE</td> <tr><td>LIKE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>LIMIT</td> <tr><td>LIMIT</td>
<td>+</td><td>NR</td><td>NR</td><td></td><td>+</td><td></td></tr> <td>+</td><td></td><td></td><td></td><td>+</td><td></td></tr>
<tr><td>LOCALTIME</td> <tr><td>LOCALTIME</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>LOCALTIMESTAMP</td> <tr><td>LOCALTIMESTAMP</td>
...@@ -564,12 +578,20 @@ The following tokens are keywords in H2: ...@@ -564,12 +578,20 @@ The following tokens are keywords in H2:
<td>+</td><td>+</td><td>+</td><td></td><td></td><td></td></tr> <td>+</td><td>+</td><td>+</td><td></td><td></td><td></td></tr>
<tr><td>ON</td> <tr><td>ON</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>OR</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>ORDER</td> <tr><td>ORDER</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>OVER</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td></td><td></td></tr>
<tr><td>PRIMARY</td> <tr><td>PRIMARY</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>QUALIFY</td> <tr><td>QUALIFY</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>+</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>REGEXP</td>
<td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>RIGHT</td>
<td>CS</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>ROW</td> <tr><td>ROW</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td></td></tr>
<tr><td>_ROWID_</td> <tr><td>_ROWID_</td>
...@@ -579,17 +601,17 @@ The following tokens are keywords in H2: ...@@ -579,17 +601,17 @@ The following tokens are keywords in H2:
<tr><td>SELECT</td> <tr><td>SELECT</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>SYSDATE</td> <tr><td>SYSDATE</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>SYSTIME</td> <tr><td>SYSTIME</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>SYSTIMESTAMP</td> <tr><td>SYSTIMESTAMP</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TABLE</td> <tr><td>TABLE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>TODAY</td> <tr><td>TODAY</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TOP</td> <tr><td>TOP</td>
<td>+</td><td></td><td></td><td></td><td></td><td></td></tr> <td>CS</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>TRUE</td> <tr><td>TRUE</td>
<td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr> <td>+</td><td>+</td><td>+</td><td>+</td><td>+</td><td>+</td></tr>
<tr><td>UNION</td> <tr><td>UNION</td>
...@@ -607,7 +629,9 @@ The following tokens are keywords in H2: ...@@ -607,7 +629,9 @@ The following tokens are keywords in H2:
</tbody> </tbody>
</table> </table>
<p> <p>
Most of them are also reserved (+) or non-reserved (NR) words in the SQL Standard. Some keywords in H2 are context-sensitive (CS), such keywords may be used as identifiers in some places,
but cannot be used as identifiers in others.
Most keywords in H2 are also reserved (+) or non-reserved (NR) words in the SQL Standard.
Newer versions of H2 may have more keywords than older ones. Newer versions of H2 may have more keywords than older ones.
</p> </p>
......
...@@ -718,9 +718,8 @@ public class Select extends Query { ...@@ -718,9 +718,8 @@ public class Select extends Query {
} }
} }
int sampleSize = getSampleSizeValue(session); int sampleSize = getSampleSizeValue(session);
LazyResultQueryFlat lazyResult = isForUpdateMvcc LazyResultQueryFlat lazyResult = new LazyResultQueryFlat(expressionArray, columnCount, sampleSize,
? new LazyResultQueryFlatForUpdate(expressionArray, sampleSize, columnCount) isForUpdateMvcc);
: new LazyResultQueryFlat(expressionArray, sampleSize, columnCount);
skipOffset(lazyResult, offset, quickOffset); skipOffset(lazyResult, offset, quickOffset);
if (result == null) { if (result == null) {
return lazyResult; return lazyResult;
...@@ -1851,13 +1850,16 @@ public class Select extends Query { ...@@ -1851,13 +1850,16 @@ public class Select extends Query {
/** /**
* Lazy execution for a flat query. * Lazy execution for a flat query.
*/ */
private class LazyResultQueryFlat extends LazyResultSelect { private final class LazyResultQueryFlat extends LazyResultSelect {
int sampleSize; private int sampleSize;
LazyResultQueryFlat(Expression[] expressions, int sampleSize, int columnCount) { private boolean forUpdate;
LazyResultQueryFlat(Expression[] expressions, int columnCount, int sampleSize, boolean forUpdate) {
super(expressions, columnCount); super(expressions, columnCount);
this.sampleSize = sampleSize; this.sampleSize = sampleSize;
this.forUpdate = forUpdate;
} }
@Override @Override
...@@ -1865,7 +1867,7 @@ public class Select extends Query { ...@@ -1865,7 +1867,7 @@ public class Select extends Query {
while ((sampleSize <= 0 || rowNumber < sampleSize) && topTableFilter.next()) { while ((sampleSize <= 0 || rowNumber < sampleSize) && topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
// This method may lock rows // This method may lock rows
if (isSelectConditionMet()) { if (forUpdate ? isConditionMetForUpdate() : isConditionMet()) {
++rowNumber; ++rowNumber;
Value[] row = new Value[columnCount]; Value[] row = new Value[columnCount];
for (int i = 0; i < columnCount; i++) { for (int i = 0; i < columnCount; i++) {
...@@ -1891,25 +1893,6 @@ public class Select extends Query { ...@@ -1891,25 +1893,6 @@ public class Select extends Query {
return false; return false;
} }
boolean isSelectConditionMet() {
return isConditionMet();
}
}
/**
* Lazy execution for a flat for update query.
*/
private final class LazyResultQueryFlatForUpdate extends LazyResultQueryFlat {
LazyResultQueryFlatForUpdate(Expression[] expressions, int sampleSize, int columnCount) {
super(expressions, sampleSize, columnCount);
}
@Override
boolean isSelectConditionMet() {
return isConditionMetForUpdate();
}
} }
/** /**
......
...@@ -1542,18 +1542,39 @@ public class JdbcDatabaseMetaData extends TraceObject implements ...@@ -1542,18 +1542,39 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* table/column/index name, in addition to the SQL-2003 keywords. The list * table/column/index name, in addition to the SQL-2003 keywords. The list
* returned is: * returned is:
* <pre> * <pre>
* INTERSECTS,LIMIT,MINUS,OFFSET,QUALIFY,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP * IF,ILIKE,INTERSECTS,
* LIMIT,
* MINUS,
* OFFSET,
* QUALIFY,
* REGEXP,_ROWID_,ROWNUM,
* SYSDATE,SYSTIME,SYSTIMESTAMP,
* TODAY,TOP
* </pre> * </pre>
* The complete list of keywords (including SQL-2003 keywords) is: * The complete list of keywords (including SQL-2003 keywords) is:
* <pre> * <pre>
* ALL, ARRAY, CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, * ALL, AND, ARRAY, AS,
* CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, DISTINCT, EXCEPT, * BETWEEN,
* EXISTS, FALSE, FETCH, FOR, FOREIGN, FROM, FULL, GROUP, HAVING, * CASE, CHECK, CONSTRAINT, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER,
* IF, INNER, INTERSECT, INTERSECTS, INTERVAL, IS, JOIN, LIKE, * DISTINCT,
* LIMIT, LOCALTIME, LOCALTIMESTAMP, MINUS, NATURAL, NOT, NULL, * EXCEPT, EXISTS,
* OFFSET, ON, ORDER, PRIMARY, QUALIFY, ROW, _ROWID_, ROWNUM, SELECT, * FALSE, FETCH, FILTER, FOR, FOREIGN, FROM, FULL,
* SYSDATE, SYSTIME, SYSTIMESTAMP, TABLE, TODAY, TOP, TRUE, UNION, * GROUP,
* UNIQUE, VALUES, WHERE, WINDOW, WITH * HAVING,
* IF, ILIKE, IN, INNER, INTERSECT, INTERSECTS, INTERVAL, IS,
* JOIN,
* LEFT, LIKE, LIMIT, LOCALTIME, LOCALTIMESTAMP,
* MINUS,
* NATURAL, NOT, NULL,
* OFFSET, ON, OR, ORDER, OVER,
* PRIMARY,
* QUALIFY,
* REGEXP, RIGHT, ROW, _ROWID_, ROWNUM,
* SELECT, SYSDATE, SYSTIME, SYSTIMESTAMP,
* TABLE, TODAY, TOP, TRUE,
* UNION, UNIQUE,
* VALUES,
* WHERE, WINDOW, WITH
* </pre> * </pre>
* *
* @return a list of additional the keywords * @return a list of additional the keywords
...@@ -1561,7 +1582,14 @@ public class JdbcDatabaseMetaData extends TraceObject implements ...@@ -1561,7 +1582,14 @@ public class JdbcDatabaseMetaData extends TraceObject implements
@Override @Override
public String getSQLKeywords() { public String getSQLKeywords() {
debugCodeCall("getSQLKeywords"); debugCodeCall("getSQLKeywords");
return "IF,INTERSECTS,LIMIT,MINUS,OFFSET,QUALIFY,_ROWID_,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP"; return "IF,ILIKE,INTERSECTS," //
+ "LIMIT," //
+ "MINUS," //
+ "OFFSET," //
+ "QUALIFY," //
+ "REGEXP,_ROWID_,ROWNUM," //
+ "SYSDATE,SYSTIME,SYSTIMESTAMP," //
+ "TODAY,TOP";
} }
/** /**
......
...@@ -362,11 +362,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -362,11 +362,7 @@ public class MVPrimaryIndex extends BaseIndex {
* @return the maximum number of rows * @return the maximum number of rows
*/ */
public long getRowCountMax() { public long getRowCountMax() {
try { return dataMap.sizeAsLongMax();
return dataMap.sizeAsLongMax();
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED, e);
}
} }
@Override @Override
......
...@@ -367,6 +367,18 @@ public class ParserUtil { ...@@ -367,6 +367,18 @@ public class ParserUtil {
} else if (eq("ARRAY", s, ignoreCase, start, end)) { } else if (eq("ARRAY", s, ignoreCase, start, end)) {
return ARRAY; return ARRAY;
} }
if (additionalKeywords) {
if (eq("AND", s, ignoreCase, start, end) || eq("AS", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER;
case 'B':
if (additionalKeywords) {
if (eq("BETWEEN", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'C': case 'C':
if (eq("CASE", s, ignoreCase, start, end)) { if (eq("CASE", s, ignoreCase, start, end)) {
...@@ -413,6 +425,11 @@ public class ParserUtil { ...@@ -413,6 +425,11 @@ public class ParserUtil {
} else if (eq("FALSE", s, ignoreCase, start, end)) { } else if (eq("FALSE", s, ignoreCase, start, end)) {
return FALSE; return FALSE;
} }
if (additionalKeywords) {
if (eq("FILTER", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'G': case 'G':
if (eq("GROUP", s, ignoreCase, start, end)) { if (eq("GROUP", s, ignoreCase, start, end)) {
...@@ -438,6 +455,11 @@ public class ParserUtil { ...@@ -438,6 +455,11 @@ public class ParserUtil {
} else if (eq("IS", s, ignoreCase, start, end)) { } else if (eq("IS", s, ignoreCase, start, end)) {
return IS; return IS;
} }
if (additionalKeywords) {
if (eq("ILIKE", s, ignoreCase, start, end) || eq("IN", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'J': case 'J':
if (eq("JOIN", s, ignoreCase, start, end)) { if (eq("JOIN", s, ignoreCase, start, end)) {
...@@ -454,6 +476,11 @@ public class ParserUtil { ...@@ -454,6 +476,11 @@ public class ParserUtil {
} else if (eq("LOCALTIMESTAMP", s, ignoreCase, start, end)) { } else if (eq("LOCALTIMESTAMP", s, ignoreCase, start, end)) {
return LOCALTIMESTAMP; return LOCALTIMESTAMP;
} }
if (additionalKeywords) {
if (eq("LEFT", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'M': case 'M':
if (eq("MINUS", s, ignoreCase, start, end)) { if (eq("MINUS", s, ignoreCase, start, end)) {
...@@ -477,6 +504,11 @@ public class ParserUtil { ...@@ -477,6 +504,11 @@ public class ParserUtil {
} else if (eq("ORDER", s, ignoreCase, start, end)) { } else if (eq("ORDER", s, ignoreCase, start, end)) {
return ORDER; return ORDER;
} }
if (additionalKeywords) {
if (eq("OR", s, ignoreCase, start, end) || eq("OVER", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'P': case 'P':
if (eq("PRIMARY", s, ignoreCase, start, end)) { if (eq("PRIMARY", s, ignoreCase, start, end)) {
...@@ -494,6 +526,11 @@ public class ParserUtil { ...@@ -494,6 +526,11 @@ public class ParserUtil {
} else if (eq("ROWNUM", s, ignoreCase, start, end)) { } else if (eq("ROWNUM", s, ignoreCase, start, end)) {
return ROWNUM; return ROWNUM;
} }
if (additionalKeywords) {
if (eq("REGEXP", s, ignoreCase, start, end) || eq("RIGHT", s, ignoreCase, start, end)) {
return KEYWORD;
}
}
return IDENTIFIER; return IDENTIFIER;
case 'S': case 'S':
if (eq("SELECT", s, ignoreCase, start, end)) { if (eq("SELECT", s, ignoreCase, start, end)) {
......
...@@ -463,7 +463,14 @@ public class TestMetaData extends TestDb { ...@@ -463,7 +463,14 @@ public class TestMetaData extends TestDb {
assertEquals("schema", meta.getSchemaTerm()); assertEquals("schema", meta.getSchemaTerm());
assertEquals("\\", meta.getSearchStringEscape()); assertEquals("\\", meta.getSearchStringEscape());
assertEquals("IF,INTERSECTS,LIMIT,MINUS,OFFSET,QUALIFY,_ROWID_,ROWNUM,SYSDATE,SYSTIME,SYSTIMESTAMP,TODAY,TOP", assertEquals("IF,ILIKE,INTERSECTS," //
+ "LIMIT," //
+ "MINUS," //
+ "OFFSET," //
+ "QUALIFY," //
+ "REGEXP,_ROWID_,ROWNUM," //
+ "SYSDATE,SYSTIME,SYSTIMESTAMP," //
+ "TODAY,TOP", //
meta.getSQLKeywords()); meta.getSQLKeywords());
assertTrue(meta.getURL().startsWith("jdbc:h2:")); assertTrue(meta.getURL().startsWith("jdbc:h2:"));
......
...@@ -87,6 +87,12 @@ public class TestKeywords extends TestBase { ...@@ -87,6 +87,12 @@ public class TestKeywords extends TestBase {
assertEquals(10, rs.getInt(1)); assertEquals(10, rs.getInt(1));
assertFalse(rs.next()); assertFalse(rs.next());
} }
try (ResultSet rs = stat.executeQuery("SELECT SUM(" + s + ") " + s + " FROM " + s + ' ' + s)) {
assertTrue(rs.next());
assertEquals(10, rs.getInt(1));
assertFalse(rs.next());
assertEquals(s, rs.getMetaData().getColumnLabel(1));
}
} catch (Throwable t) { } catch (Throwable t) {
throw new AssertionError(s + " cannot be used as identifier.", t); throw new AssertionError(s + " cannot be used as identifier.", t);
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论