提交 cc12be67 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Parse row values with ROW() and with unparenthesed syntax in more places

上级 31fac352
...@@ -129,6 +129,7 @@ import org.h2.command.ddl.TruncateTable; ...@@ -129,6 +129,7 @@ import org.h2.command.ddl.TruncateTable;
import org.h2.command.dml.AlterTableSet; import org.h2.command.dml.AlterTableSet;
import org.h2.command.dml.BackupCommand; import org.h2.command.dml.BackupCommand;
import org.h2.command.dml.Call; import org.h2.command.dml.Call;
import org.h2.command.dml.CommandWithValues;
import org.h2.command.dml.Delete; import org.h2.command.dml.Delete;
import org.h2.command.dml.ExecuteProcedure; import org.h2.command.dml.ExecuteProcedure;
import org.h2.command.dml.Explain; import org.h2.command.dml.Explain;
...@@ -1491,10 +1492,7 @@ public class Parser { ...@@ -1491,10 +1492,7 @@ public class Parser {
command.setKeys(keys); command.setKeys(keys);
} }
if (readIf(VALUES)) { if (readIf(VALUES)) {
do { parseValuesForCommand(command);
read(OPEN_PAREN);
command.addRow(parseValuesForInsert());
} while (readIf(COMMA));
} else { } else {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
} }
...@@ -1681,11 +1679,7 @@ public class Parser { ...@@ -1681,11 +1679,7 @@ public class Parser {
Expression[] expr = {}; Expression[] expr = {};
command.addRow(expr); command.addRow(expr);
} else if (readIf(VALUES)) { } else if (readIf(VALUES)) {
read(OPEN_PAREN); parseValuesForCommand(command);
do {
command.addRow(parseValuesForInsert());
// the following condition will allow (..),; and (..);
} while (readIf(COMMA) && readIf(OPEN_PAREN));
} else if (readIf("SET")) { } else if (readIf("SET")) {
if (columns != null) { if (columns != null) {
throw getSyntaxError(); throw getSyntaxError();
...@@ -1724,28 +1718,35 @@ public class Parser { ...@@ -1724,28 +1718,35 @@ public class Parser {
command.setColumns(columns); command.setColumns(columns);
} }
if (readIf(VALUES)) { if (readIf(VALUES)) {
do { parseValuesForCommand(command);
read(OPEN_PAREN);
command.addRow(parseValuesForInsert());
} while (readIf(COMMA));
} else { } else {
command.setQuery(parseSelect()); command.setQuery(parseSelect());
} }
return command; return command;
} }
private Expression[] parseValuesForInsert() { private void parseValuesForCommand(CommandWithValues command) {
ArrayList<Expression> values = Utils.newSmallArrayList(); ArrayList<Expression> values = Utils.newSmallArrayList();
if (!readIf(CLOSE_PAREN)) { do {
do { values.clear();
if (readIf("DEFAULT")) { boolean multiColumn;
values.add(null); if (readIf(ROW)) {
} else { read(OPEN_PAREN);
values.add(readExpression()); multiColumn = true;
} else {
multiColumn = readIf(OPEN_PAREN);
}
if (multiColumn) {
if (!readIf(CLOSE_PAREN)) {
do {
values.add(readIf("DEFAULT") ? null : readExpression());
} while (readIfMore(false));
} }
} while (readIfMore(false)); } else {
} values.add(readIf("DEFAULT") ? null : readExpression());
return values.toArray(new Expression[0]); }
command.addRow(values.toArray(new Expression[0]));
} while (readIf(COMMA));
} }
private TableFilter readTableFilter() { private TableFilter readTableFilter() {
...@@ -5840,7 +5841,13 @@ public class Parser { ...@@ -5840,7 +5841,13 @@ public class Parser {
do { do {
int i = 0; int i = 0;
ArrayList<Expression> row = Utils.newSmallArrayList(); ArrayList<Expression> row = Utils.newSmallArrayList();
boolean multiColumn = readIf(OPEN_PAREN); boolean multiColumn;
if (readIf(ROW)) {
read(OPEN_PAREN);
multiColumn = true;
} else {
multiColumn = readIf(OPEN_PAREN);
}
do { do {
Expression expr = readExpression(); Expression expr = readExpression();
expr = expr.optimize(session); expr = expr.optimize(session);
......
/*
* Copyright 2004-2019 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.command.dml;
import java.util.ArrayList;
import org.h2.command.Prepared;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.util.Utils;
/**
* Command that supports VALUES clause.
*/
public abstract class CommandWithValues extends Prepared {
protected final ArrayList<Expression[]> valuesExpressionList = Utils.newSmallArrayList();
/**
* Creates new instance of command with VALUES clause.
*
* @param session
* the session
*/
protected CommandWithValues(Session session) {
super(session);
}
/**
* Add a row to this command.
*
* @param expr
* the list of values
*/
public void addRow(Expression[] expr) {
valuesExpressionList.add(expr);
}
}
...@@ -12,7 +12,6 @@ import org.h2.api.ErrorCode; ...@@ -12,7 +12,6 @@ import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.Command; import org.h2.command.Command;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared;
import org.h2.engine.GeneratedKeys; import org.h2.engine.GeneratedKeys;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Right; import org.h2.engine.Right;
...@@ -35,7 +34,6 @@ import org.h2.table.Column; ...@@ -35,7 +34,6 @@ import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -43,11 +41,10 @@ import org.h2.value.ValueNull; ...@@ -43,11 +41,10 @@ import org.h2.value.ValueNull;
* This class represents the statement * This class represents the statement
* INSERT * INSERT
*/ */
public class Insert extends Prepared implements ResultTarget { public class Insert extends CommandWithValues implements ResultTarget {
private Table table; private Table table;
private Column[] columns; private Column[] columns;
private final ArrayList<Expression[]> list = Utils.newSmallArrayList();
private Query query; private Query query;
private boolean sortedInsertMode; private boolean sortedInsertMode;
private int rowNumber; private int rowNumber;
...@@ -117,15 +114,6 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -117,15 +114,6 @@ public class Insert extends Prepared implements ResultTarget {
duplicateKeyAssignmentMap.put(column, expression); duplicateKeyAssignmentMap.put(column, expression);
} }
/**
* Add a row to this merge statement.
*
* @param expr the list of values
*/
public void addRow(Expression[] expr) {
list.add(expr);
}
@Override @Override
public int update() { public int update() {
Index index = null; Index index = null;
...@@ -157,14 +145,14 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -157,14 +145,14 @@ public class Insert extends Prepared implements ResultTarget {
rowNumber = 0; rowNumber = 0;
GeneratedKeys generatedKeys = session.getGeneratedKeys(); GeneratedKeys generatedKeys = session.getGeneratedKeys();
generatedKeys.initialize(table); generatedKeys.initialize(table);
int listSize = list.size(); int listSize = valuesExpressionList.size();
if (listSize > 0) { if (listSize > 0) {
Mode mode = session.getDatabase().getMode(); Mode mode = session.getDatabase().getMode();
int columnLen = columns.length; int columnLen = columns.length;
for (int x = 0; x < listSize; x++) { for (int x = 0; x < listSize; x++) {
generatedKeys.nextRow(); generatedKeys.nextRow();
Row newRow = table.getTemplateRow(); Row newRow = table.getTemplateRow();
Expression[] expr = list.get(x); Expression[] expr = valuesExpressionList.get(x);
setCurrentRowNumber(x + 1); setCurrentRowNumber(x + 1);
for (int i = 0; i < columnLen; i++) { for (int i = 0; i < columnLen; i++) {
Column c = columns[i]; Column c = columns[i];
...@@ -294,13 +282,13 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -294,13 +282,13 @@ public class Insert extends Prepared implements ResultTarget {
if (sortedInsertMode) { if (sortedInsertMode) {
buff.append("SORTED "); buff.append("SORTED ");
} }
if (!list.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
buff.append("VALUES "); buff.append("VALUES ");
int row = 0; int row = 0;
if (list.size() > 1) { if (valuesExpressionList.size() > 1) {
buff.append('\n'); buff.append('\n');
} }
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (row++ > 0) { if (row++ > 0) {
buff.append(",\n"); buff.append(",\n");
} }
...@@ -317,15 +305,15 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -317,15 +305,15 @@ public class Insert extends Prepared implements ResultTarget {
@Override @Override
public void prepare() { public void prepare() {
if (columns == null) { if (columns == null) {
if (!list.isEmpty() && list.get(0).length == 0) { if (!valuesExpressionList.isEmpty() && valuesExpressionList.get(0).length == 0) {
// special case where table is used as a sequence // special case where table is used as a sequence
columns = new Column[0]; columns = new Column[0];
} else { } else {
columns = table.getColumns(); columns = table.getColumns();
} }
} }
if (!list.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (expr.length != columns.length) { if (expr.length != columns.length) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
...@@ -400,7 +388,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -400,7 +388,7 @@ public class Insert extends Prepared implements ResultTarget {
ArrayList<String> variableNames = new ArrayList<>( ArrayList<String> variableNames = new ArrayList<>(
duplicateKeyAssignmentMap.size()); duplicateKeyAssignmentMap.size());
Expression[] row = (currentRow == null) ? list.get((int) getCurrentRowNumber() - 1) Expression[] row = (currentRow == null) ? valuesExpressionList.get((int) getCurrentRowNumber() - 1)
: new Expression[columns.length]; : new Expression[columns.length];
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
String key = table.getSchema().getName() + "." + String key = table.getSchema().getName() + "." +
......
...@@ -27,20 +27,18 @@ import org.h2.table.Column; ...@@ -27,20 +27,18 @@ import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
* This class represents the statement * This class represents the statement
* MERGE * MERGE
*/ */
public class Merge extends Prepared { public class Merge extends CommandWithValues {
private Table targetTable; private Table targetTable;
private TableFilter targetTableFilter; private TableFilter targetTableFilter;
private Column[] columns; private Column[] columns;
private Column[] keys; private Column[] keys;
private final ArrayList<Expression[]> valuesExpressionList = Utils.newSmallArrayList();
private Query query; private Query query;
private Prepared update; private Prepared update;
...@@ -72,15 +70,6 @@ public class Merge extends Prepared { ...@@ -72,15 +70,6 @@ public class Merge extends Prepared {
this.query = query; this.query = query;
} }
/**
* Add a row to this merge statement.
*
* @param expr the list of values
*/
public void addRow(Expression[] expr) {
valuesExpressionList.add(expr);
}
@Override @Override
public int update() { public int update() {
int count; int count;
......
...@@ -25,18 +25,16 @@ import org.h2.result.Row; ...@@ -25,18 +25,16 @@ import org.h2.result.Row;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.Utils;
import org.h2.value.Value; import org.h2.value.Value;
/** /**
* This class represents the MySQL-compatibility REPLACE statement * This class represents the MySQL-compatibility REPLACE statement
*/ */
public class Replace extends Prepared { public class Replace extends CommandWithValues {
private Table table; private Table table;
private Column[] columns; private Column[] columns;
private Column[] keys; private Column[] keys;
private final ArrayList<Expression[]> list = Utils.newSmallArrayList();
private Query query; private Query query;
private Prepared update; private Prepared update;
...@@ -68,15 +66,6 @@ public class Replace extends Prepared { ...@@ -68,15 +66,6 @@ public class Replace extends Prepared {
this.query = query; this.query = query;
} }
/**
* Add a row to this replace statement.
*
* @param expr the list of values
*/
public void addRow(Expression[] expr) {
list.add(expr);
}
@Override @Override
public int update() { public int update() {
int count = 0; int count = 0;
...@@ -84,10 +73,10 @@ public class Replace extends Prepared { ...@@ -84,10 +73,10 @@ public class Replace extends Prepared {
session.getUser().checkRight(table, Right.UPDATE); session.getUser().checkRight(table, Right.UPDATE);
setCurrentRowNumber(0); setCurrentRowNumber(0);
Mode mode = session.getDatabase().getMode(); Mode mode = session.getDatabase().getMode();
if (!list.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
for (int x = 0, size = list.size(); x < size; x++) { for (int x = 0, size = valuesExpressionList.size(); x < size; x++) {
setCurrentRowNumber(x + 1); setCurrentRowNumber(x + 1);
Expression[] expr = list.get(x); Expression[] expr = valuesExpressionList.get(x);
Row newRow = table.getTemplateRow(); Row newRow = table.getTemplateRow();
for (int i = 0, len = columns.length; i < len; i++) { for (int i = 0, len = columns.length; i < len; i++) {
Column c = columns[i]; Column c = columns[i];
...@@ -214,10 +203,10 @@ public class Replace extends Prepared { ...@@ -214,10 +203,10 @@ public class Replace extends Prepared {
} }
buff.append(')'); buff.append(')');
buff.append('\n'); buff.append('\n');
if (!list.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
buff.append("VALUES "); buff.append("VALUES ");
int row = 0; int row = 0;
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (row++ > 0) { if (row++ > 0) {
buff.append(", "); buff.append(", ");
} }
...@@ -234,15 +223,15 @@ public class Replace extends Prepared { ...@@ -234,15 +223,15 @@ public class Replace extends Prepared {
@Override @Override
public void prepare() { public void prepare() {
if (columns == null) { if (columns == null) {
if (!list.isEmpty() && list.get(0).length == 0) { if (!valuesExpressionList.isEmpty() && valuesExpressionList.get(0).length == 0) {
// special case where table is used as a sequence // special case where table is used as a sequence
columns = new Column[0]; columns = new Column[0];
} else { } else {
columns = table.getColumns(); columns = table.getColumns();
} }
} }
if (!list.isEmpty()) { if (!valuesExpressionList.isEmpty()) {
for (Expression[] expr : list) { for (Expression[] expr : valuesExpressionList) {
if (expr.length != columns.length) { if (expr.length != columns.length) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
......
...@@ -23,8 +23,7 @@ INSERT INTO VERSION VALUES ...@@ -23,8 +23,7 @@ INSERT INTO VERSION VALUES
(134, '1.4.184', '2014-12-19'), (134, '1.4.184', '2014-12-19'),
(133, '1.4.183', '2014-12-13'), (133, '1.4.183', '2014-12-13'),
(132, '1.4.182', '2014-10-17'), (132, '1.4.182', '2014-10-17'),
(131, '1.4.181', '2014-08-06'), (131, '1.4.181', '2014-08-06');
;
CREATE TABLE CHANNEL(TITLE VARCHAR, LINK VARCHAR, DESC VARCHAR, CREATE TABLE CHANNEL(TITLE VARCHAR, LINK VARCHAR, DESC VARCHAR,
LANGUAGE VARCHAR, PUB TIMESTAMP, LAST TIMESTAMP, AUTHOR VARCHAR); LANGUAGE VARCHAR, PUB TIMESTAMP, LAST TIMESTAMP, AUTHOR VARCHAR);
......
...@@ -154,8 +154,8 @@ public class TestScript extends TestDb { ...@@ -154,8 +154,8 @@ public class TestScript extends TestDb {
"dropDomain", "dropIndex", "dropSchema", "truncateTable" }) { "dropDomain", "dropIndex", "dropSchema", "truncateTable" }) {
testScript("ddl/" + s + ".sql"); testScript("ddl/" + s + ".sql");
} }
for (String s : new String[] { "delete", "error_reporting", "insertIgnore", "merge", "mergeUsing", "replace", for (String s : new String[] { "delete", "error_reporting", "insert", "insertIgnore", "merge", "mergeUsing",
"script", "select", "show", "table", "with" }) { "replace", "script", "select", "show", "table", "with" }) {
testScript("dml/" + s + ".sql"); testScript("dml/" + s + ".sql");
} }
for (String s : new String[] { "help" }) { for (String s : new String[] { "help" }) {
......
-- Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE TABLE TEST(A INT, B INT);
> ok
INSERT INTO TEST VALUES ROW (1, 2), (3, 4), ROW (5, 6);
> update count: 3
INSERT INTO TEST(a) VALUES 7;
> update count: 1
INSERT INTO TEST(a) VALUES 8, 9;
> update count: 2
TABLE TEST;
> A B
> - ----
> 1 2
> 3 4
> 5 6
> 7 null
> 8 null
> 9 null
> rows: 6
DROP TABLE TEST;
> ok
...@@ -537,3 +537,16 @@ VALUES (1, 2); ...@@ -537,3 +537,16 @@ VALUES (1, 2);
> -- -- > -- --
> 1 2 > 1 2
> rows: 1 > rows: 1
VALUES ROW (1, 2);
> C1 C2
> -- --
> 1 2
> rows: 1
VALUES 1, 2;
> C1
> --
> 1
> 2
> rows: 2
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论