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

Merge pull request #1115 from manuhode/manuh-issue#1095

Add support for INSERT IGNORE from SELECT in MySQL Mode
...@@ -23,6 +23,7 @@ import org.h2.expression.Expression; ...@@ -23,6 +23,7 @@ import org.h2.expression.Expression;
import org.h2.expression.ExpressionColumn; import org.h2.expression.ExpressionColumn;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.expression.SequenceValue; import org.h2.expression.SequenceValue;
import org.h2.expression.ValueExpression;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.index.PageDataIndex; import org.h2.index.PageDataIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
...@@ -183,7 +184,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -183,7 +184,7 @@ public class Insert extends Prepared implements ResultTarget {
try { try {
table.addRow(session, newRow); table.addRow(session, newRow);
} catch (DbException de) { } catch (DbException de) {
if (handleOnDuplicate(de)) { if (handleOnDuplicate(de, null)) {
// MySQL returns 2 for updated row // MySQL returns 2 for updated row
// TODO: detect no-op change // TODO: detect no-op change
rowNumber++; rowNumber++;
...@@ -207,9 +208,20 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -207,9 +208,20 @@ public class Insert extends Prepared implements ResultTarget {
while (rows.next()) { while (rows.next()) {
generatedKeys.nextRow(); generatedKeys.nextRow();
Value[] r = rows.currentRow(); Value[] r = rows.currentRow();
Row newRow = addRowImpl(r); try {
if (newRow != null) { Row newRow = addRowImpl(r);
generatedKeys.confirmRow(newRow); if (newRow != null) {
generatedKeys.confirmRow(newRow);
}
} catch (DbException de) {
if (handleOnDuplicate(de, r)) {
// MySQL returns 2 for updated row
// TODO: detect no-op change
rowNumber++;
} else {
// INSERT IGNORE case
rowNumber--;
}
} }
} }
rows.close(); rows.close();
...@@ -365,9 +377,10 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -365,9 +377,10 @@ public class Insert extends Prepared implements ResultTarget {
/** /**
* @param de duplicate key exception * @param de duplicate key exception
* @param currentRow current row values (optional)
* @return {@code true} if row was updated, {@code false} if row was ignored * @return {@code true} if row was updated, {@code false} if row was ignored
*/ */
private boolean handleOnDuplicate(DbException de) { private boolean handleOnDuplicate(DbException de, Value[] currentRow) {
if (de.getErrorCode() != ErrorCode.DUPLICATE_KEY_1) { if (de.getErrorCode() != ErrorCode.DUPLICATE_KEY_1) {
throw de; throw de;
} }
...@@ -381,13 +394,20 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -381,13 +394,20 @@ public class Insert extends Prepared implements ResultTarget {
ArrayList<String> variableNames = new ArrayList<>( ArrayList<String> variableNames = new ArrayList<>(
duplicateKeyAssignmentMap.size()); duplicateKeyAssignmentMap.size());
Expression[] row = list.get(getCurrentRowNumber() - 1); Expression[] row = (currentRow == null) ? list.get(getCurrentRowNumber() - 1)
: 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() + "." +
table.getName() + "." + columns[i].getName(); table.getName() + "." + columns[i].getName();
variableNames.add(key); variableNames.add(key);
session.setVariable(key, Value value;
row[i].getValue(session)); if (currentRow != null) {
value = currentRow[i];
row[i] = ValueExpression.get(value);
} else {
value = row[i].getValue(session);
}
session.setVariable(key, value);
} }
StatementBuilder buff = new StatementBuilder("UPDATE "); StatementBuilder buff = new StatementBuilder("UPDATE ");
...@@ -403,7 +423,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -403,7 +423,7 @@ public class Insert extends Prepared implements ResultTarget {
throw DbException.getUnsupportedException( throw DbException.getUnsupportedException(
"Unable to apply ON DUPLICATE KEY UPDATE, no index found!"); "Unable to apply ON DUPLICATE KEY UPDATE, no index found!");
} }
buff.append(prepareUpdateCondition(foundIndex).getSQL()); buff.append(prepareUpdateCondition(foundIndex, row).getSQL());
String sql = buff.toString(); String sql = buff.toString();
Update command = (Update) session.prepare(sql); Update command = (Update) session.prepare(sql);
command.setUpdateToCurrentValuesReturnsZero(true); command.setUpdateToCurrentValuesReturnsZero(true);
...@@ -418,7 +438,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -418,7 +438,7 @@ public class Insert extends Prepared implements ResultTarget {
return result; return result;
} }
private Expression prepareUpdateCondition(Index foundIndex) { private Expression prepareUpdateCondition(Index foundIndex, Expression[] row) {
// MVPrimaryIndex is playing fast and loose with it's implementation of // MVPrimaryIndex is playing fast and loose with it's implementation of
// the Index interface. // the Index interface.
// It returns all of the columns in the table when we call // It returns all of the columns in the table when we call
...@@ -440,7 +460,6 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -440,7 +460,6 @@ public class Insert extends Prepared implements ResultTarget {
indexedColumns = foundIndex.getColumns(); indexedColumns = foundIndex.getColumns();
} }
Expression[] row = list.get(getCurrentRowNumber() - 1);
Expression condition = null; Expression condition = null;
for (Column column : indexedColumns) { for (Column column : indexedColumns) {
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), ExpressionColumn expr = new ExpressionColumn(session.getDatabase(),
......
...@@ -39,3 +39,60 @@ SELECT * FROM TEST ORDER BY ID; ...@@ -39,3 +39,60 @@ SELECT * FROM TEST ORDER BY ID;
> 4 40 > 4 40
> 5 52 > 5 52
> rows (ordered): 5 > rows (ordered): 5
CREATE TABLE TESTREF(ID BIGINT PRIMARY KEY, VALUE INT NOT NULL);
> ok
INSERT INTO TESTREF VALUES (1, 11), (2, 21), (6, 61), (7, 71);
> update count: 4
INSERT INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> exception DUPLICATE_KEY_1
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> 5 52
> rows (ordered): 5
INSERT IGNORE INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> update count: 2
INSERT IGNORE INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF;
> ok
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 10
> 2 20
> 3 30
> 4 40
> 5 52
> 6 61
> 7 71
> rows (ordered): 7
INSERT INTO TESTREF VALUES (8, 81), (9, 91);
> update count: 2
INSERT INTO TEST (ID, VALUE) SELECT ID, VALUE FROM TESTREF ON DUPLICATE KEY UPDATE VALUE=83;
> update count: 10
SELECT * FROM TEST ORDER BY ID;
> ID VALUE
> -- -----
> 1 83
> 2 83
> 3 30
> 4 40
> 5 52
> 6 83
> 7 83
> 8 81
> 9 91
> rows (ordered): 9
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论