提交 31fac352 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Parse table value constructor in more places

上级 ea64e353
...@@ -21,6 +21,10 @@ Change Log ...@@ -21,6 +21,10 @@ Change Log
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul> <ul>
<li>Issue #1677: Unable to use VALUES keyword in WHERE clause
</li>
<li>Issue #1672: Deadlock on MVStore close in TestOutOfMemory
</li>
<li>Issue #1665: TestCrashAPI: NPE with ENUM in MINUS operator <li>Issue #1665: TestCrashAPI: NPE with ENUM in MINUS operator
</li> </li>
<li>Issue #1602: Combine type, precision, scale, display size and extTypeInfo into one object <li>Issue #1602: Combine type, precision, scale, display size and extTypeInfo into one object
......
...@@ -415,11 +415,13 @@ To keep the content of an in-memory database as long as the virtual machine is a ...@@ -415,11 +415,13 @@ To keep the content of an in-memory database as long as the virtual machine is a
<p> <p>
The database files can be encrypted. The database files can be encrypted.
Three encryption algorithms are supported: Three encryption algorithms are supported:
</p>
<ul> <ul>
<li>"AES" - also known as Rijndael, only AES-128 is implemented.</li> <li>"AES" - also known as Rijndael, only AES-128 is implemented.</li>
<li>"XTEA" - the 32 round version.</li> <li>"XTEA" - the 32 round version.</li>
<li>"FOG" - pseudo-encryption only useful for hiding data from a text editor.</li> <li>"FOG" - pseudo-encryption only useful for hiding data from a text editor.</li>
</ul> </ul>
<p>
To use file encryption, you need to specify the encryption algorithm (the 'cipher') To use file encryption, you need to specify the encryption algorithm (the 'cipher')
and the file password (in addition to the user password) when connecting to the database. and the file password (in addition to the user password) when connecting to the database.
</p> </p>
...@@ -906,8 +908,10 @@ or the SQL statement <code>SET MODE MySQL</code>. Use this mode for compatibilit ...@@ -906,8 +908,10 @@ or the SQL statement <code>SET MODE MySQL</code>. Use this mode for compatibilit
digits are not truncated, but the value is rounded. digits are not truncated, but the value is rounded.
</li><li>Concatenating <code>NULL</code> with another value </li><li>Concatenating <code>NULL</code> with another value
results in the other value. results in the other value.
</li><li>ON DUPLICATE KEY UPDATE is supported in INSERT statements. </li><li>ON DUPLICATE KEY UPDATE is supported in INSERT statements, due to this feature VALUES has special non-standard
</li><li>INSERT IGNORE is partially supported and may be used to skip rows with duplicate keys if ON DUPLICATE KEY UPDATE is not specified. meaning is some contexts.
</li><li>INSERT IGNORE is partially supported and may be used to skip rows with duplicate keys if ON DUPLICATE KEY
UPDATE is not specified.
</li><li>REGEXP_REPLACE() uses \ for back-references for compatibility with MariaDB. </li><li>REGEXP_REPLACE() uses \ for back-references for compatibility with MariaDB.
</li><li>Datetime value functions return the same value within a command. </li><li>Datetime value functions return the same value within a command.
</li></ul> </li></ul>
...@@ -1467,6 +1471,7 @@ For some examples, have a look at the code in <code>org.h2.test.db.TestTableEngi ...@@ -1467,6 +1471,7 @@ For some examples, have a look at the code in <code>org.h2.test.db.TestTableEngi
<p> <p>
In order to create your own TableEngine, you need to implement the <code>org.h2.api.TableEngine</code> interface e.g. In order to create your own TableEngine, you need to implement the <code>org.h2.api.TableEngine</code> interface e.g.
something like this: something like this:
</p>
<pre> <pre>
package acme; package acme;
public static class MyTableEngine implements org.h2.api.TableEngine { public static class MyTableEngine implements org.h2.api.TableEngine {
...@@ -1480,12 +1485,13 @@ public static class MyTableEngine implements org.h2.api.TableEngine { ...@@ -1480,12 +1485,13 @@ public static class MyTableEngine implements org.h2.api.TableEngine {
} }
} }
</pre> </pre>
<p>
and then create the table from SQL like this: and then create the table from SQL like this:
</p>
<pre> <pre>
CREATE TABLE TEST(ID INT, NAME VARCHAR) CREATE TABLE TEST(ID INT, NAME VARCHAR)
ENGINE "acme.MyTableEngine"; ENGINE "acme.MyTableEngine";
</pre> </pre>
</p>
<p> <p>
It is also possible to pass in parameters to the table engine, like so: It is also possible to pass in parameters to the table engine, like so:
</p> </p>
......
...@@ -253,7 +253,8 @@ import org.h2.value.ValueTimestampTimeZone; ...@@ -253,7 +253,8 @@ import org.h2.value.ValueTimestampTimeZone;
public class Parser { public class Parser {
private static final String WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS = private static final String WITH_STATEMENT_SUPPORTS_LIMITED_SUB_STATEMENTS =
"WITH statement supports only SELECT, TABLE, CREATE TABLE, INSERT, UPDATE, MERGE or DELETE statements"; "WITH statement supports only SELECT, TABLE, VALUES, " +
"CREATE TABLE, INSERT, UPDATE, MERGE or DELETE statements";
// used during the tokenizer phase // used during the tokenizer phase
private static final int CHAR_END = 1, CHAR_VALUE = 2, CHAR_QUOTED = 3; private static final int CHAR_END = 1, CHAR_VALUE = 2, CHAR_QUOTED = 3;
...@@ -755,11 +756,8 @@ public class Parser { ...@@ -755,11 +756,8 @@ public class Parser {
case FROM: case FROM:
case SELECT: case SELECT:
case TABLE: case TABLE:
c = parseSelect();
break;
case VALUES: case VALUES:
read(); c = parseSelect();
c = parseValues();
break; break;
case WITH: case WITH:
read(); read();
...@@ -1450,6 +1448,7 @@ public class Parser { ...@@ -1450,6 +1448,7 @@ public class Parser {
switch (currentTokenType) { switch (currentTokenType) {
case FROM: case FROM:
case SELECT: case SELECT:
case VALUES:
case WITH: case WITH:
select = true; select = true;
break; break;
...@@ -2350,6 +2349,7 @@ public class Parser { ...@@ -2350,6 +2349,7 @@ public class Parser {
case FROM: case FROM:
case SELECT: case SELECT:
case TABLE: case TABLE:
case VALUES:
case WITH: case WITH:
case OPEN_PAREN: case OPEN_PAREN:
Query query = parseSelect(); Query query = parseSelect();
...@@ -2696,6 +2696,8 @@ public class Parser { ...@@ -2696,6 +2696,8 @@ public class Parser {
command.setExpressions(expressions); command.setExpressions(expressions);
setSQL(command, "TABLE", start); setSQL(command, "TABLE", start);
return command; return command;
} else if (readIf(VALUES)) {
return parseValues();
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -3936,8 +3938,12 @@ public class Parser { ...@@ -3936,8 +3938,12 @@ public class Parser {
read(); read();
break; break;
case VALUES: case VALUES:
if (database.getMode().onDuplicateKeyUpdate) {
read(); read();
r = readKeywordFunction("VALUES"); r = readKeywordFunction("VALUES");
} else {
r = new Subquery(parseSelect());
}
break; break;
case CASE: case CASE:
read(); read();
...@@ -5823,14 +5829,12 @@ public class Parser { ...@@ -5823,14 +5829,12 @@ public class Parser {
TableFilter filter = parseValuesTable(0); TableFilter filter = parseValuesTable(0);
command.setWildcard(); command.setWildcard();
command.addTableFilter(filter, true); command.addTableFilter(filter, true);
command.init();
return command; return command;
} }
private TableFilter parseValuesTable(int orderInFrom) { private TableFilter parseValuesTable(int orderInFrom) {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
TableFunction tf = (TableFunction) Function.getFunction(database, TableFunction tf = (TableFunction) Function.getFunction(database, "TABLE");
"TABLE");
ArrayList<Column> columns = Utils.newSmallArrayList(); ArrayList<Column> columns = Utils.newSmallArrayList();
ArrayList<ArrayList<Expression>> rows = Utils.newSmallArrayList(); ArrayList<ArrayList<Expression>> rows = Utils.newSmallArrayList();
do { do {
...@@ -5885,9 +5889,7 @@ public class Parser { ...@@ -5885,9 +5889,7 @@ public class Parser {
tf.setColumns(columns); tf.setColumns(columns);
tf.doneWithParameters(); tf.doneWithParameters();
Table table = new FunctionTable(mainSchema, session, tf, tf); Table table = new FunctionTable(mainSchema, session, tf, tf);
return new TableFilter(session, table, null, return new TableFilter(session, table, null, rightsChecked, currentSelect, orderInFrom, null);
rightsChecked, currentSelect, orderInFrom,
null);
} }
private Call parseCall() { private Call parseCall() {
...@@ -6163,7 +6165,7 @@ public class Parser { ...@@ -6163,7 +6165,7 @@ public class Parser {
while (readIf(OPEN_PAREN)) { while (readIf(OPEN_PAREN)) {
parentheses++; parentheses++;
} }
if (isToken(SELECT)) { if (isToken(SELECT) || isToken(VALUES)) {
p = parseWithQuery(); p = parseWithQuery();
} else if (isToken(TABLE)) { } else if (isToken(TABLE)) {
int index = lastParseIndex; int index = lastParseIndex;
......
...@@ -509,3 +509,31 @@ SELECT RAND() A, RAND() + 1 B, RAND() + 1 C, RAND() D, RAND() + 2 E, RAND() + 3 ...@@ -509,3 +509,31 @@ SELECT RAND() A, RAND() + 1 B, RAND() + 1 C, RAND() D, RAND() + 2 E, RAND() + 3
> rows: 1 > rows: 1
@reconnect on @reconnect on
CREATE TABLE TEST (A INT, B INT, C INT);
> ok
INSERT INTO TEST VALUES (11, 12, 13), (21, 22, 23), (31, 32, 33);
> update count: 3
SELECT * FROM TEST WHERE (A, B) IN (VALUES (11, 12), (21, 22), (41, 42));
> A B C
> -- -- --
> 11 12 13
> 21 22 23
> rows: 2
SELECT * FROM TEST WHERE (A, B) = (VALUES (11, 12));
> A B C
> -- -- --
> 11 12 13
> rows: 1
DROP TABLE TEST;
> ok
VALUES (1, 2);
> C1 C2
> -- --
> 1 2
> rows: 1
...@@ -146,6 +146,12 @@ WITH CTE_TEST AS (TABLE TEST) ((TABLE CTE_TEST)); ...@@ -146,6 +146,12 @@ WITH CTE_TEST AS (TABLE TEST) ((TABLE CTE_TEST));
> 1 2 > 1 2
> rows: 1 > rows: 1
WITH CTE_TEST AS (VALUES (1, 2)) ((SELECT * FROM CTE_TEST));
> C1 C2
> -- --
> 1 2
> rows: 1
WITH CTE_TEST AS (TABLE TEST) ((SELECT A, B FROM CTE_TEST2)); WITH CTE_TEST AS (TABLE TEST) ((SELECT A, B FROM CTE_TEST2));
> exception TABLE_OR_VIEW_NOT_FOUND_1 > exception TABLE_OR_VIEW_NOT_FOUND_1
......
...@@ -806,4 +806,4 @@ econd irst bcef ordinality nord unnest ...@@ -806,4 +806,4 @@ econd irst bcef ordinality nord unnest
analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan analyst occupation distributive josaph aor engineer sajeewa isuru randil kevin doctor businessman artist ashan
corrupts splitted disruption unintentional octets preconditions predicates subq objectweb insn opcodes corrupts splitted disruption unintentional octets preconditions predicates subq objectweb insn opcodes
preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl rgr preserves masking holder unboxing avert iae transformed subtle reevaluate exclusions subclause ftbl rgr
presorted inclusion presorted inclusion contexts
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论