提交 4617c019 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add partial support for INSERT IGNORE in MySQL mode

Only duplicate key errors are ignored.
上级 01397c72
......@@ -1220,6 +1220,9 @@ public class Parser {
private Insert parseInsert() {
Insert command = new Insert(session);
currentPrepared = command;
if (database.getMode().onDuplicateKeyUpdate && readIf("IGNORE")) {
command.setIgnore(true);
}
read("INTO");
Table table = readTableOrView();
command.setTable(table);
......
......@@ -57,6 +57,11 @@ public class Insert extends Prepared implements ResultTarget {
*/
private HashMap<Column, Expression> duplicateKeyAssignmentMap;
/**
* For MySQL-style INSERT IGNORE
*/
private boolean ignore;
public Insert(Session session) {
super(session);
}
......@@ -77,6 +82,14 @@ public class Insert extends Prepared implements ResultTarget {
this.columns = columns;
}
/**
* Sets MySQL-style INSERT IGNORE mode
* @param ignore ignore errors
*/
public void setIgnore(boolean ignore) {
this.ignore = ignore;
}
public void setQuery(Query query) {
this.query = query;
}
......@@ -160,7 +173,11 @@ public class Insert extends Prepared implements ResultTarget {
try {
table.addRow(session, newRow);
} catch (DbException de) {
handleOnDuplicate(de);
if (!handleOnDuplicate(de)) {
// INSERT IGNORE case
rowNumber--;
continue;
}
}
session.log(table, UndoLogRecord.INSERT, newRow);
table.fireAfterRow(session, null, newRow, false);
......@@ -321,12 +338,19 @@ public class Insert extends Prepared implements ResultTarget {
duplicateKeyAssignmentMap.isEmpty();
}
private void handleOnDuplicate(DbException de) {
/**
* @param de duplicate key exception
* @return {@code true} if row was updated, {@code false} if row was ignored
*/
private boolean handleOnDuplicate(DbException de) {
if (de.getErrorCode() != ErrorCode.DUPLICATE_KEY_1) {
throw de;
}
if (duplicateKeyAssignmentMap == null ||
duplicateKeyAssignmentMap.isEmpty()) {
if (ignore) {
return false;
}
throw de;
}
......@@ -364,6 +388,7 @@ public class Insert extends Prepared implements ResultTarget {
for (String variableName : variableNames) {
session.setVariable(variableName, ValueNull.INSTANCE);
}
return true;
}
private Expression prepareUpdateCondition(Index foundIndex) {
......
......@@ -158,7 +158,7 @@ public class Mode {
public boolean isolationLevelInSelectOrInsertStatement;
/**
* MySQL style INSERT ... ON DUPLICATE KEY UPDATE ...
* MySQL style INSERT ... ON DUPLICATE KEY UPDATE ... and INSERT IGNORE
*/
public boolean onDuplicateKeyUpdate;
......
......@@ -141,7 +141,7 @@ public class TestScript extends TestBase {
"parsedatetime", "quarter", "second", "week", "year" }) {
testScript("functions/timeanddate/" + s + ".sql");
}
for (String s : new String[] { "with", "mergeUsing" }) {
for (String s : new String[] { "insertIgnore", "mergeUsing", "with" }) {
testScript("dml/" + s + ".sql");
}
deleteDb("script");
......
-- 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
--
SET MODE MySQL;
> ok
CREATE TABLE TEST(ID BIGINT PRIMARY KEY, VALUE INT NOT NULL);
> ok
INSERT INTO TEST VALUES (1, 10), (2, 20), (3, 30), (4, 40);
> update count: 4
INSERT INTO TEST VALUES (3, 31), (5, 51);
> exception
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> rows (ordered): 4
INSERT IGNORE INTO TEST VALUES (3, 32), (5, 52);
> update count: 1
INSERT IGNORE INTO TEST VALUES (4, 43);
> ok
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> 5 52
> rows (ordered): 5
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论