提交 675317bb authored 作者: Thomas Mueller's avatar Thomas Mueller

MVCC: concurrently updating a row could result in the row to appear deleted in…

MVCC: concurrently updating a row could result in the row to appear deleted in the second connection, if there are multiple unique indexes (or a primary key and at least one unique index). Thanks a lot to Teruo for the patch!
上级 f54bc593
...@@ -419,6 +419,8 @@ public abstract class Table extends SchemaObjectBase { ...@@ -419,6 +419,8 @@ public abstract class Table extends SchemaObjectBase {
* new row,... * new row,...
*/ */
public void updateRows(Prepared prepared, Session session, RowList rows) { public void updateRows(Prepared prepared, Session session, RowList rows) {
// in case we need to undo the update
int rollback = session.getUndoLogPos();
// remove the old rows // remove the old rows
int rowScanCount = 0; int rowScanCount = 0;
for (rows.reset(); rows.hasNext();) { for (rows.reset(); rows.hasNext();) {
...@@ -437,7 +439,14 @@ public abstract class Table extends SchemaObjectBase { ...@@ -437,7 +439,14 @@ public abstract class Table extends SchemaObjectBase {
} }
rows.next(); rows.next();
Row n = rows.next(); Row n = rows.next();
addRow(session, n); try {
addRow(session, n);
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1) {
session.rollbackTo(rollback, false);
}
throw e;
}
session.log(this, UndoLogRecord.INSERT, n); session.log(this, UndoLogRecord.INSERT, n);
} }
} }
......
...@@ -24,10 +24,13 @@ public class TestMvcc3 extends TestBase { ...@@ -24,10 +24,13 @@ public class TestMvcc3 extends TestBase {
* @param a ignored * @param a ignored
*/ */
public static void main(String... a) throws Exception { public static void main(String... a) throws Exception {
TestBase.createCaller().init().test(); TestBase test = TestBase.createCaller().init();
test.config.mvcc = true;
test.test();
} }
public void test() throws SQLException { public void test() throws SQLException {
testConcurrentUpdate();
testInsertUpdateRollback(); testInsertUpdateRollback();
testCreateTableAsSelect(); testCreateTableAsSelect();
testSequence(); testSequence();
...@@ -36,6 +39,50 @@ public class TestMvcc3 extends TestBase { ...@@ -36,6 +39,50 @@ public class TestMvcc3 extends TestBase {
deleteDb("mvcc3"); deleteDb("mvcc3");
} }
private void testConcurrentUpdate() throws SQLException {
if (!config.mvcc) {
return;
}
deleteDb("mvcc3");
Connection c1 = getConnection("mvcc3");
c1.setAutoCommit(false);
Statement s1 = c1.createStatement();
Connection c2 = getConnection("mvcc3");
c2.setAutoCommit(false);
Statement s2 = c2.createStatement();
s1.execute("create table test(id int primary key, name varchar) as select x, x from system_range(1, 2)");
s1.execute("create unique index on test(name)");
s1.executeUpdate("update test set name = 100 where id = 1");
try {
s2.executeUpdate("update test set name = 100 where id = 2");
fail();
} catch (SQLException e) {
// expected
}
ResultSet rs = s1.executeQuery("select * from test order by id");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertEquals("100", rs.getString(2));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertEquals("2", rs.getString(2));
assertFalse(rs.next());
rs = s2.executeQuery("select * from test order by id");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertEquals("1", rs.getString(2));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertEquals("2", rs.getString(2));
assertFalse(rs.next());
c1.close();
c2.close();
}
private void testInsertUpdateRollback() throws SQLException { private void testInsertUpdateRollback() throws SQLException {
if (!config.mvcc) { if (!config.mvcc) {
return; return;
...@@ -188,6 +235,7 @@ public class TestMvcc3 extends TestBase { ...@@ -188,6 +235,7 @@ public class TestMvcc3 extends TestBase {
assertEquals(1, rs.getInt(1)); assertEquals(1, rs.getInt(1));
conn.close(); conn.close();
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论