提交 83b86da8 authored 作者: Thomas Mueller's avatar Thomas Mueller

New system property h2.selectForUpdateMvcc, the default is false (the feature is disabled).

上级 43e31e6f
...@@ -718,14 +718,16 @@ public class TableFilter implements ColumnResolver { ...@@ -718,14 +718,16 @@ public class TableFilter implements ColumnResolver {
return false; return false;
} }
public void lockRow() { public void lockRow(ArrayList<Row> rows) {
if (state == FOUND) { if (state == FOUND) {
Row row = get(); rows.add(get());
}
}
public void lockRows(ArrayList<Row> forUpdateRows) {
for (Row row : forUpdateRows) {
table.removeRow(session, row); table.removeRow(session, row);
table.addRow(session, row); table.addRow(session, row);
if (join != null) {
join.lockRow();
}
} }
} }
......
...@@ -61,23 +61,11 @@ public class TestMvcc1 extends TestBase { ...@@ -61,23 +61,11 @@ public class TestMvcc1 extends TestBase {
if (!config.mvcc) { if (!config.mvcc) {
return; return;
} }
// TODO Prio 1: row level locking for update / delete (as PostgreSQL)
// TODO Prio 1: document: exclusive table lock still used when altering // TODO Prio 1: document: exclusive table lock still used when altering
// tables, adding indexes, select ... for update; table level locks are // tables, adding indexes, select ... for update; table level locks are
// checked // checked
// TODO Prio 1: free up disk space (for deleted rows and old versions of
// updated rows) on commit
// TODO Prio 1: ScanIndex: never remove uncommitted data from cache
// (lost sessionId)
// TODO Prio 1: test with Hibernate
// TODO Prio 2: if MVCC is used, rows of transactions need to fit in // TODO Prio 2: if MVCC is used, rows of transactions need to fit in
// memory // memory
// TODO Prio 2: write the log only when committed; remove restriction at
// Record.canRemove
// TODO Prio 2: getRowCount: different row count for different indexes
// (MultiVersionIndex)
// TODO Prio 2: getRowCount: different row count for different sessions:
// TableLink (use different connections?)
// TODO Prio 2: getFirst / getLast in MultiVersionIndex // TODO Prio 2: getFirst / getLast in MultiVersionIndex
// TODO Prio 2: snapshot isolation (currently read-committed, not // TODO Prio 2: snapshot isolation (currently read-committed, not
// repeatable read) // repeatable read)
......
...@@ -9,7 +9,8 @@ package org.h2.test.mvcc; ...@@ -9,7 +9,8 @@ package org.h2.test.mvcc;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
...@@ -28,7 +29,10 @@ public class TestMvcc2 extends TestBase { ...@@ -28,7 +29,10 @@ public class TestMvcc2 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(); System.setProperty("h2.selectForUpdateMvcc", "true");
TestBase test = TestBase.createCaller().init();
test.config.mvcc = true;
test.test();
} }
public void test() throws SQLException { public void test() throws SQLException {
...@@ -36,6 +40,7 @@ public class TestMvcc2 extends TestBase { ...@@ -36,6 +40,7 @@ public class TestMvcc2 extends TestBase {
return; return;
} }
deleteDb("mvcc2"); deleteDb("mvcc2");
testSelectForUpdate();
testInsertUpdateRollback(); testInsertUpdateRollback();
testInsertRollback(); testInsertRollback();
deleteDb("mvcc2"); deleteDb("mvcc2");
...@@ -45,6 +50,54 @@ public class TestMvcc2 extends TestBase { ...@@ -45,6 +50,54 @@ public class TestMvcc2 extends TestBase {
return getConnection("mvcc2"); return getConnection("mvcc2");
} }
private void testSelectForUpdate() throws SQLException {
if (!SysProperties.SELECT_FOR_UPDATE_MVCC) {
return;
}
Connection conn = getConnection();
Connection conn2 = getConnection();
Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key, name varchar)");
conn.setAutoCommit(false);
stat.execute("insert into test select x, 'Hello' from system_range(1, 10)");
stat.execute("select * from test where id = 3 for update");
conn.commit();
try {
stat.execute("select sum(id) from test for update");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.FEATURE_NOT_SUPPORTED_1, e.getErrorCode());
}
try {
stat.execute("select distinct id from test for update");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.FEATURE_NOT_SUPPORTED_1, e.getErrorCode());
}
try {
stat.execute("select id from test group by id for update");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.FEATURE_NOT_SUPPORTED_1, e.getErrorCode());
}
try {
stat.execute("select t1.id from test t1, test t2 for update");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.FEATURE_NOT_SUPPORTED_1, e.getErrorCode());
}
stat.execute("select * from test where id = 3 for update");
conn2.setAutoCommit(false);
conn2.createStatement().execute("select * from test where id = 4 for update");
try {
conn2.createStatement().execute("select * from test where id = 3 for update");
fail();
} catch (SQLException e) {
assertEquals(ErrorCode.CONCURRENT_UPDATE_1, e.getErrorCode());
}
conn.close();
}
private void testInsertUpdateRollback() throws SQLException { private void testInsertUpdateRollback() throws SQLException {
Connection conn = getConnection(); Connection conn = getConnection();
conn.setAutoCommit(false); conn.setAutoCommit(false);
......
...@@ -84,7 +84,7 @@ public class TestFuzzOptimizations extends TestBase { ...@@ -84,7 +84,7 @@ public class TestFuzzOptimizations extends TestBase {
String[] columns = new String[] { "a", "b", "c" }; String[] columns = new String[] { "a", "b", "c" };
String[] values = new String[] { null, "0", "0", "1", "2", "10", "a", "?" }; String[] values = new String[] { null, "0", "0", "1", "2", "10", "a", "?" };
String[] compares = new String[] { "in(", "not in(", "=", "=", ">", "<", ">=", "<=", "<>", "in(select", "not in(select" }; String[] compares = new String[] { "in(", "not in(", "=", "=", ">", "<", ">=", "<=", "<>", "in(select", "not in(select" };
int size = getSize(1000, 10000); int size = getSize(500, 5000);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
long seed = seedGenerator.nextLong(); long seed = seedGenerator.nextLong();
println("seed: " + seed); println("seed: " + seed);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论