提交 861aec17 authored 作者: Noel Grandin's avatar Noel Grandin

Fix bug in picking the right index for INSERT..ON DUPLICATE KEY UPDATE when…

Fix bug in picking the right index for INSERT..ON DUPLICATE KEY UPDATE when there are both UNIQUE and PRIMARY KEY constraints.
上级 47598ca2
...@@ -25,6 +25,8 @@ Change Log ...@@ -25,6 +25,8 @@ Change Log
</li> </li>
<li>PR #364: fix compare TIMESTAMP WITH TIMEZONE <li>PR #364: fix compare TIMESTAMP WITH TIMEZONE
</li> </li>
<li>Fix bug in picking the right index for INSERT..ON DUPLICATE KEY UPDATE when there are both UNIQUE and PRIMARY KEY constraints.
</li>
<li>Issue #380: Error Analyzer doesn't show source code <li>Issue #380: Error Analyzer doesn't show source code
</li> </li>
<li>Remove the "TIMESTAMP UTC" datatype, an experiment that was never finished. <li>Remove the "TIMESTAMP UTC" datatype, an experiment that was never finished.
......
...@@ -7,7 +7,6 @@ package org.h2.command.dml; ...@@ -7,7 +7,6 @@ package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import org.h2.api.ErrorCode; 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;
...@@ -23,6 +22,7 @@ import org.h2.expression.ExpressionColumn; ...@@ -23,6 +22,7 @@ import org.h2.expression.ExpressionColumn;
import org.h2.expression.Parameter; import org.h2.expression.Parameter;
import org.h2.index.Index; import org.h2.index.Index;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.db.MVPrimaryIndex;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.ResultTarget; import org.h2.result.ResultTarget;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -340,7 +340,7 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -340,7 +340,7 @@ public class Insert extends Prepared implements ResultTarget {
buff.append(column.getSQL()).append("=").append(ex.getSQL()); buff.append(column.getSQL()).append("=").append(ex.getSQL());
} }
buff.append(" WHERE "); buff.append(" WHERE ");
Index foundIndex = searchForUpdateIndex(); Index foundIndex = (Index) de.getSource();
if (foundIndex == null) { if (foundIndex == null) {
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!");
...@@ -358,44 +358,36 @@ public class Insert extends Prepared implements ResultTarget { ...@@ -358,44 +358,36 @@ public class Insert extends Prepared implements ResultTarget {
} }
} }
private Index searchForUpdateIndex() { private Expression prepareUpdateCondition(Index foundIndex) {
Index foundIndex = null; // MVPrimaryIndex is playing fast and loose with it's implementation of
for (Index index : table.getIndexes()) { // the Index interface.
if (index.getIndexType().isPrimaryKey() || index.getIndexType().isUnique()) { // It returns all of the columns in the table when we call
for (Column indexColumn : index.getColumns()) { // getIndexColumns() or getColumns().
for (Column insertColumn : columns) { // Don't have time right now to fix that, so just special-case it.
if (indexColumn.getName().equals(insertColumn.getName())) { final Column[] indexedColumns;
foundIndex = index; if (foundIndex instanceof MVPrimaryIndex) {
break; MVPrimaryIndex foundMV = (MVPrimaryIndex) foundIndex;
} indexedColumns = new Column[] { foundMV.getIndexColumns()[foundMV
foundIndex = null; .getMainIndexColumn()].column };
} } else {
if (foundIndex == null) { indexedColumns = foundIndex.getColumns();
break;
}
}
if (foundIndex != null) {
break;
}
}
}
return foundIndex;
} }
private Expression prepareUpdateCondition(Index foundIndex) {
Expression condition = null; Expression condition = null;
for (Column column : foundIndex.getColumns()) { for (Column column : indexedColumns) {
ExpressionColumn expr = new ExpressionColumn(session.getDatabase(), ExpressionColumn expr = new ExpressionColumn(session.getDatabase(),
table.getSchema().getName(), table.getName(), column.getName()); table.getSchema().getName(), table.getName(),
column.getName());
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
if (expr.getColumnName().equals(columns[i].getName())) { if (expr.getColumnName().equals(columns[i].getName())) {
if (condition == null) { if (condition == null) {
condition = new Comparison(session, Comparison.EQUAL, condition = new Comparison(session, Comparison.EQUAL,
expr, list.get(getCurrentRowNumber() - 1)[i++]); expr, list.get(getCurrentRowNumber() - 1)[i++]);
} else { } else {
condition = new ConditionAndOr(ConditionAndOr.AND, condition, condition = new ConditionAndOr(ConditionAndOr.AND,
new Comparison(session, Comparison.EQUAL, condition,
expr, list.get(0)[i++])); new Comparison(session, Comparison.EQUAL, expr,
list.get(0)[i++]));
} }
} }
} }
......
...@@ -10,7 +10,6 @@ import java.sql.PreparedStatement; ...@@ -10,7 +10,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
...@@ -37,6 +36,7 @@ public class TestDuplicateKeyUpdate extends TestBase { ...@@ -37,6 +36,7 @@ public class TestDuplicateKeyUpdate extends TestBase {
testDuplicateExpression(conn); testDuplicateExpression(conn);
testOnDuplicateKeyInsertBatch(conn); testOnDuplicateKeyInsertBatch(conn);
testOnDuplicateKeyInsertMultiValue(conn); testOnDuplicateKeyInsertMultiValue(conn);
testPrimaryKeyAndUniqueKey(conn);
conn.close(); conn.close();
deleteDb("duplicateKeyUpdate"); deleteDb("duplicateKeyUpdate");
} }
...@@ -243,4 +243,19 @@ public class TestDuplicateKeyUpdate extends TestBase { ...@@ -243,4 +243,19 @@ public class TestDuplicateKeyUpdate extends TestBase {
stat.execute("drop table test"); stat.execute("drop table test");
} }
private void testPrimaryKeyAndUniqueKey(Connection conn) throws SQLException
{
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE test (id INT, dup INT, counter INT, PRIMARY KEY(id), UNIQUE(dup))");
stat.execute("INSERT INTO test (id, dup, counter) VALUES (1, 1, 1)");
stat.execute("INSERT INTO test (id, dup, counter) VALUES (2, 1, 1) ON DUPLICATE KEY UPDATE counter = counter + VALUES(counter)");
// Check result
ResultSet rs = stat.executeQuery("SELECT counter FROM test ORDER BY id");
rs.next();
assertEquals(2, rs.getInt(1));
assertEquals(false, rs.next());
stat.execute("drop table test");
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论