提交 803781b5 authored 作者: Thomas Mueller's avatar Thomas Mueller

start to implement row level locks

上级 4908d970
...@@ -176,10 +176,12 @@ public abstract class Command implements CommandInterface { ...@@ -176,10 +176,12 @@ public abstract class Command implements CommandInterface {
session.commit(false); session.commit(false);
} else if (session.getDatabase().getMultiThreaded()) { } else if (session.getDatabase().getMultiThreaded()) {
Database db = session.getDatabase(); Database db = session.getDatabase();
if (db != null && db.getLockMode() == Constants.LOCK_MODE_READ_COMMITTED) { if (db != null) {
if (db.getLockMode() == Constants.LOCK_MODE_READ_COMMITTED) {
session.unlockReadLocks(); session.unlockReadLocks();
} }
} }
}
if (trace.isInfoEnabled()) { if (trace.isInfoEnabled()) {
long time = System.currentTimeMillis() - startTime; long time = System.currentTimeMillis() - startTime;
if (time > Constants.SLOW_QUERY_LIMIT_MS) { if (time > Constants.SLOW_QUERY_LIMIT_MS) {
......
...@@ -334,6 +334,13 @@ public class Constants { ...@@ -334,6 +334,13 @@ public class Constants {
*/ */
public static final int LOCK_MODE_READ_COMMITTED = 3; public static final int LOCK_MODE_READ_COMMITTED = 3;
/**
* The lock mode that means row level locks are used if possible.
* This lock mode is similar to read committed, but row level locks are
* used instead of table level locks.
*/
public static final int LOCK_MODE_ROW = 4;
/** /**
* The lock mode that means table level locking is used for reads and * The lock mode that means table level locking is used for reads and
* writes. * writes.
......
...@@ -1741,7 +1741,17 @@ public class Database implements DataHandler { ...@@ -1741,7 +1741,17 @@ public class Database implements DataHandler {
return maxMemoryUndo; return maxMemoryUndo;
} }
public void setLockMode(int lockMode) { public void setLockMode(int lockMode) throws SQLException {
switch (lockMode) {
case Constants.LOCK_MODE_OFF:
case Constants.LOCK_MODE_READ_COMMITTED:
case Constants.LOCK_MODE_TABLE:
case Constants.LOCK_MODE_TABLE_GC:
case Constants.LOCK_MODE_ROW:
break;
default:
throw Message.getInvalidValueException("lock mode", "" + lockMode);
}
this.lockMode = lockMode; this.lockMode = lockMode;
} }
......
...@@ -684,6 +684,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -684,6 +684,7 @@ public class JdbcConnection extends TraceObject implements Connection {
transactionIsolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED; transactionIsolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
break; break;
case Constants.LOCK_MODE_READ_COMMITTED: case Constants.LOCK_MODE_READ_COMMITTED:
case Constants.LOCK_MODE_ROW:
transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED; transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED;
break; break;
case Constants.LOCK_MODE_TABLE: case Constants.LOCK_MODE_TABLE:
......
...@@ -377,13 +377,17 @@ public class TableData extends Table implements RecordReader { ...@@ -377,13 +377,17 @@ public class TableData extends Table implements RecordReader {
} }
} else { } else {
if (lockExclusive == null) { if (lockExclusive == null) {
if (lockMode == Constants.LOCK_MODE_READ_COMMITTED && !database.getMultiThreaded() && !database.isMultiVersion()) { if (lockMode == Constants.LOCK_MODE_READ_COMMITTED || lockMode == Constants.LOCK_MODE_ROW) {
if (!database.getMultiThreaded() && !database.isMultiVersion()) {
// READ_COMMITTED read locks are acquired but they // READ_COMMITTED read locks are acquired but they
// are released immediately // are released immediately
// when allowing only one thread, no read locks are // when allowing only one thread, no read locks are
// required // required
// row level locks work like read committed
return; return;
} else if (!lockShared.contains(session)) { }
}
if (!lockShared.contains(session)) {
traceLock(session, exclusive, "ok"); traceLock(session, exclusive, "ok");
session.addLock(this); session.addLock(this);
lockShared.add(session); lockShared.add(session);
......
...@@ -72,6 +72,7 @@ import org.h2.test.jdbcx.TestXASimple; ...@@ -72,6 +72,7 @@ import org.h2.test.jdbcx.TestXASimple;
import org.h2.test.mvcc.TestMvcc1; import org.h2.test.mvcc.TestMvcc1;
import org.h2.test.mvcc.TestMvcc2; import org.h2.test.mvcc.TestMvcc2;
import org.h2.test.mvcc.TestMvcc3; import org.h2.test.mvcc.TestMvcc3;
import org.h2.test.rowlock.TestRowLocks;
import org.h2.test.server.TestNestedLoop; import org.h2.test.server.TestNestedLoop;
import org.h2.test.server.TestPgServer; import org.h2.test.server.TestPgServer;
import org.h2.test.server.TestWeb; import org.h2.test.server.TestWeb;
...@@ -266,6 +267,8 @@ java org.h2.test.TestAll timer ...@@ -266,6 +267,8 @@ java org.h2.test.TestAll timer
/* /*
row level locking
run the performance tests as part of the unit test run the performance tests as part of the unit test
switch to JDK 1.6 by default switch to JDK 1.6 by default
...@@ -611,10 +614,11 @@ Roadmap: ...@@ -611,10 +614,11 @@ Roadmap:
new TestWeb().runTest(this); new TestWeb().runTest(this);
new TestPgServer().runTest(this); new TestPgServer().runTest(this);
// mvcc // mvcc & row level locking
new TestMvcc1().runTest(this); new TestMvcc1().runTest(this);
new TestMvcc2().runTest(this); new TestMvcc2().runTest(this);
new TestMvcc3().runTest(this); new TestMvcc3().runTest(this);
new TestRowLocks().runTest(this);
// synth // synth
new TestCrashAPI().runTest(this); new TestCrashAPI().runTest(this);
......
...@@ -184,7 +184,9 @@ public abstract class TestBase { ...@@ -184,7 +184,9 @@ public abstract class TestBase {
if (config.textStorage) { if (config.textStorage) {
url += ";STORAGE=TEXT"; url += ";STORAGE=TEXT";
} }
if (url.indexOf("LOCK_TIMEOUT=") < 0) {
url += ";LOCK_TIMEOUT=50"; url += ";LOCK_TIMEOUT=50";
}
if (admin) { if (admin) {
url += ";LOG=" + config.logMode; url += ";LOG=" + config.logMode;
} }
...@@ -198,7 +200,7 @@ public abstract class TestBase { ...@@ -198,7 +200,7 @@ public abstract class TestBase {
// force operations to disk // force operations to disk
url += ";MAX_OPERATION_MEMORY=1"; url += ";MAX_OPERATION_MEMORY=1";
} }
if (config.mvcc) { if (config.mvcc && url.indexOf("MVCC=") < 0) {
url += ";MVCC=TRUE"; url += ";MVCC=TRUE";
} }
if (config.cache2Q) { if (config.cache2Q) {
...@@ -657,6 +659,24 @@ public abstract class TestBase { ...@@ -657,6 +659,24 @@ public abstract class TestBase {
assertFalse(rs.next()); assertFalse(rs.next());
} }
/**
* Check that the result set of a query is exactly this value.
*
* @param stat the statement
* @param sql the SQL statement to execute
* @param expected the expected result value
* @throws Exception if a different result value was returned
*/
protected void assertResult(Statement stat, String sql, String expected) throws Exception {
ResultSet rs = stat.executeQuery(sql);
if (rs.next()) {
String actual = rs.getString(1);
assertEquals(expected, actual);
} else {
assertEquals(null, expected);
}
}
/** /**
* Check if the result set meta data is correct. * Check if the result set meta data is correct.
* *
......
...@@ -74,7 +74,7 @@ public class TestCases extends TestBase { ...@@ -74,7 +74,7 @@ public class TestCases extends TestBase {
sql = "delete from " + table; sql = "delete from " + table;
} }
stat.execute(sql); stat.execute(sql);
stat.execute("script to 'test.sql'"); stat.execute("script to '" + baseDir + "/test.sql'");
} }
conn.close(); conn.close();
} }
......
...@@ -104,11 +104,11 @@ public class TestCsv extends TestBase { ...@@ -104,11 +104,11 @@ public class TestCsv extends TestBase {
list.add(new String[]{a, b}); list.add(new String[]{a, b});
prep.execute(); prep.execute();
} }
stat.execute("CALL CSVWRITE('test.csv', 'SELECT * FROM test', 'UTF-8', '|', '#')"); stat.execute("CALL CSVWRITE('" + baseDir + "/test.csv', 'SELECT * FROM test', 'UTF-8', '|', '#')");
Csv csv = Csv.getInstance(); Csv csv = Csv.getInstance();
csv.setFieldSeparatorRead('|'); csv.setFieldSeparatorRead('|');
csv.setFieldDelimiter('#'); csv.setFieldDelimiter('#');
ResultSet rs = csv.read("test.csv", null, "UTF-8"); ResultSet rs = csv.read(baseDir + "/test.csv", null, "UTF-8");
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
assertTrue(rs.next()); assertTrue(rs.next());
String[] pair = (String[]) list.get(i); String[] pair = (String[]) list.get(i);
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
package org.h2.test.mvcc; package org.h2.test.mvcc;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
...@@ -15,7 +14,6 @@ import java.util.Random; ...@@ -15,7 +14,6 @@ import java.util.Random;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
/** /**
* Basic MVCC (multi version concurrency) test cases. * Basic MVCC (multi version concurrency) test cases.
...@@ -31,9 +29,8 @@ public class TestMvcc1 extends TestBase { ...@@ -31,9 +29,8 @@ public class TestMvcc1 extends TestBase {
} }
private void testSetMode() throws Exception { private void testSetMode() throws Exception {
DeleteDbFiles.execute(null, "test", true); deleteDb("mvcc1");
Class.forName("org.h2.Driver"); c1 = getConnection("mvcc1;MVCC=FALSE");
c1 = DriverManager.getConnection("jdbc:h2:test", "sa", "sa");
Statement stat = c1.createStatement(); Statement stat = c1.createStatement();
ResultSet rs = stat.executeQuery("select * from information_schema.settings where name='MVCC'"); ResultSet rs = stat.executeQuery("select * from information_schema.settings where name='MVCC'");
rs.next(); rs.next();
...@@ -78,11 +75,10 @@ public class TestMvcc1 extends TestBase { ...@@ -78,11 +75,10 @@ public class TestMvcc1 extends TestBase {
// TODO test: one thread appends, the other // TODO test: one thread appends, the other
// selects new data (select * from test where id > ?) and deletes // selects new data (select * from test where id > ?) and deletes
DeleteDbFiles.execute(null, "test", true); deleteDb("mvcc1");
Class.forName("org.h2.Driver"); c1 = getConnection("mvcc1;MVCC=TRUE;LOCK_TIMEOUT=10");
c1 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE;LOCK_TIMEOUT=10", "sa", "sa");
s1 = c1.createStatement(); s1 = c1.createStatement();
c2 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE;LOCK_TIMEOUT=10", "sa", "sa"); c2 = getConnection("mvcc1;MVCC=TRUE;LOCK_TIMEOUT=10");
s2 = c2.createStatement(); s2 = c2.createStatement();
c1.setAutoCommit(false); c1.setAutoCommit(false);
c2.setAutoCommit(false); c2.setAutoCommit(false);
...@@ -91,10 +87,10 @@ public class TestMvcc1 extends TestBase { ...@@ -91,10 +87,10 @@ public class TestMvcc1 extends TestBase {
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID))"); s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID))");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
c1.commit(); c1.commit();
test(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello"); assertResult(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello");
s1.execute("UPDATE TEST SET NAME = 'Hallo' WHERE ID=1"); s1.execute("UPDATE TEST SET NAME = 'Hallo' WHERE ID=1");
test(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello"); assertResult(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello");
test(s1, "SELECT NAME FROM TEST WHERE ID=1", "Hallo"); assertResult(s1, "SELECT NAME FROM TEST WHERE ID=1", "Hallo");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
...@@ -133,9 +129,9 @@ public class TestMvcc1 extends TestBase { ...@@ -133,9 +129,9 @@ public class TestMvcc1 extends TestBase {
s1.execute("create table test(id int, name varchar)"); s1.execute("create table test(id int, name varchar)");
s1.execute("insert into test values(1, 'A'), (2, 'B')"); s1.execute("insert into test values(1, 'A'), (2, 'B')");
c1.commit(); c1.commit();
test(s1, "select count(*) from test where name<>'C'", "2"); assertResult(s1, "select count(*) from test where name<>'C'", "2");
s2.execute("update test set name='B2' where id=2"); s2.execute("update test set name='B2' where id=2");
test(s1, "select count(*) from test where name<>'C'", "2"); assertResult(s1, "select count(*) from test where name<>'C'", "2");
c2.commit(); c2.commit();
s2.execute("drop table test"); s2.execute("drop table test");
c2.rollback(); c2.rollback();
...@@ -160,8 +156,8 @@ public class TestMvcc1 extends TestBase { ...@@ -160,8 +156,8 @@ public class TestMvcc1 extends TestBase {
s1.execute("create table test(id int primary key, name varchar(255))"); s1.execute("create table test(id int primary key, name varchar(255))");
s2.execute("insert into test values(4, 'Hello')"); s2.execute("insert into test values(4, 'Hello')");
c2.rollback(); c2.rollback();
test(s1, "select count(*) from test where name = 'Hello'", "0"); assertResult(s1, "select count(*) from test where name = 'Hello'", "0");
test(s2, "select count(*) from test where name = 'Hello'", "0"); assertResult(s2, "select count(*) from test where name = 'Hello'", "0");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
...@@ -169,10 +165,10 @@ public class TestMvcc1 extends TestBase { ...@@ -169,10 +165,10 @@ public class TestMvcc1 extends TestBase {
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))");
s1.execute("INSERT INTO TEST VALUES(1, 'Test')"); s1.execute("INSERT INTO TEST VALUES(1, 'Test')");
c1.commit(); c1.commit();
test(s1, "select max(id) from test", "1"); assertResult(s1, "select max(id) from test", "1");
s1.execute("INSERT INTO TEST VALUES(2, 'World')"); s1.execute("INSERT INTO TEST VALUES(2, 'World')");
c1.rollback(); c1.rollback();
test(s1, "select max(id) from test", "1"); assertResult(s1, "select max(id) from test", "1");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
...@@ -181,7 +177,7 @@ public class TestMvcc1 extends TestBase { ...@@ -181,7 +177,7 @@ public class TestMvcc1 extends TestBase {
s1.execute("create table test as select * from table(id int=(1, 2))"); s1.execute("create table test as select * from table(id int=(1, 2))");
s1.execute("update test set id=1 where id=1"); s1.execute("update test set id=1 where id=1");
s1.execute("select max(id) from test"); s1.execute("select max(id) from test");
test(s1, "select max(id) from test", "2"); assertResult(s1, "select max(id) from test", "2");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
...@@ -189,12 +185,12 @@ public class TestMvcc1 extends TestBase { ...@@ -189,12 +185,12 @@ public class TestMvcc1 extends TestBase {
s1.execute("CREATE TABLE TEST(ID INT)"); s1.execute("CREATE TABLE TEST(ID INT)");
s1.execute("INSERT INTO TEST VALUES(1)"); s1.execute("INSERT INTO TEST VALUES(1)");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "1");
s1.executeUpdate("DELETE FROM TEST"); s1.executeUpdate("DELETE FROM TEST");
test(s2, "SELECT COUNT(*) FROM TEST", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "1");
test(s1, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s1, "SELECT COUNT(*) FROM TEST", "0");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "0");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
...@@ -203,39 +199,39 @@ public class TestMvcc1 extends TestBase { ...@@ -203,39 +199,39 @@ public class TestMvcc1 extends TestBase {
s1.execute("INSERT INTO TEST VALUES(1)"); s1.execute("INSERT INTO TEST VALUES(1)");
c1.commit(); c1.commit();
s1.execute("DELETE FROM TEST"); s1.execute("DELETE FROM TEST");
test(s1, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s1, "SELECT COUNT(*) FROM TEST", "0");
c1.commit(); c1.commit();
test(s1, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s1, "SELECT COUNT(*) FROM TEST", "0");
s1.execute("INSERT INTO TEST VALUES(1)"); s1.execute("INSERT INTO TEST VALUES(1)");
s1.execute("DELETE FROM TEST"); s1.execute("DELETE FROM TEST");
c1.commit(); c1.commit();
test(s1, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s1, "SELECT COUNT(*) FROM TEST", "0");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)"); s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')");
test(s2, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "0");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST", "2"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "2");
s1.execute("INSERT INTO TEST VALUES(3, '!')"); s1.execute("INSERT INTO TEST VALUES(3, '!')");
c1.rollback(); c1.rollback();
test(s2, "SELECT COUNT(*) FROM TEST", "2"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "2");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)"); s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
s1.execute("DELETE FROM TEST"); s1.execute("DELETE FROM TEST");
test(s2, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "0");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "0");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
s1.execute("CREATE TABLE TEST(ID INT IDENTITY, NAME VARCHAR)"); s1.execute("CREATE TABLE TEST(ID INT IDENTITY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST(NAME) VALUES('Ruebezahl')"); s1.execute("INSERT INTO TEST(NAME) VALUES('Ruebezahl')");
test(s2, "SELECT COUNT(*) FROM TEST", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST", "0");
test(s1, "SELECT COUNT(*) FROM TEST", "1"); assertResult(s1, "SELECT COUNT(*) FROM TEST", "1");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
...@@ -333,22 +329,22 @@ public class TestMvcc1 extends TestBase { ...@@ -333,22 +329,22 @@ public class TestMvcc1 extends TestBase {
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR)"); s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
test(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "0");
test(s1, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1"); assertResult(s1, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1");
test(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE NAME!='X'", "1");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)"); s1.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
test(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "0"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "0");
test(s1, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1"); assertResult(s1, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1");
c1.commit(); c1.commit();
test(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1");
test(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1"); assertResult(s2, "SELECT COUNT(*) FROM TEST WHERE ID<100", "1");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
...@@ -356,10 +352,10 @@ public class TestMvcc1 extends TestBase { ...@@ -356,10 +352,10 @@ public class TestMvcc1 extends TestBase {
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID, NAME))"); s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID, NAME))");
s1.execute("INSERT INTO TEST VALUES(1, 'Hello')"); s1.execute("INSERT INTO TEST VALUES(1, 'Hello')");
c1.commit(); c1.commit();
test(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello"); assertResult(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello");
s1.execute("UPDATE TEST SET NAME = 'Hallo' WHERE ID=1"); s1.execute("UPDATE TEST SET NAME = 'Hallo' WHERE ID=1");
test(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello"); assertResult(s2, "SELECT NAME FROM TEST WHERE ID=1", "Hello");
test(s1, "SELECT NAME FROM TEST WHERE ID=1", "Hallo"); assertResult(s1, "SELECT NAME FROM TEST WHERE ID=1", "Hallo");
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
...@@ -400,19 +396,4 @@ public class TestMvcc1 extends TestBase { ...@@ -400,19 +396,4 @@ public class TestMvcc1 extends TestBase {
} }
private void test(Statement stat, String sql, String expected) throws Exception {
ResultSet rs = stat.executeQuery(sql);
if (rs.next()) {
String s = rs.getString(1);
if (expected == null) {
throw new Error("expected: no rows, got: " + s);
} else if (!expected.equals(s)) {
throw new Error("expected: " + expected + ", got: " + s);
}
} else {
if (expected != null) {
throw new Error("expected: " + expected + ", got: no rows");
}
}
}
} }
/*
* Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.rowlock;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
/**
* Row level locking tests.
*/
public class TestRowLocks extends TestBase {
private Connection c1, c2;
private Statement s1;
public void test() throws Exception {
testSetMode();
testCases();
}
private void testSetMode() throws Exception {
DeleteDbFiles.execute(null, "test", true);
Class.forName("org.h2.Driver");
c1 = DriverManager.getConnection("jdbc:h2:test", "sa", "sa");
Statement stat = c1.createStatement();
stat.execute("SET LOCK_MODE 4");
ResultSet rs = stat.executeQuery("call lock_mode()");
rs.next();
assertEquals("4", rs.getString(1));
c1.close();
}
private void testCases() throws Exception {
deleteDb("rowLocks");
c1 = getConnection("rowLocks");
s1 = c1.createStatement();
s1.execute("SET LOCK_MODE 4");
c2 = getConnection("rowLocks");
// s2 = c2.createStatement();
c1.setAutoCommit(false);
c2.setAutoCommit(false);
c1.close();
c2.close();
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License, Version 1.0,,
and under the Eclipse Public License, Version 1.0
(http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;">
Row level locking tests.
</body></html>
\ No newline at end of file
--- special grammar and test cases --------------------------------------------------------------------------------------------- --- special grammar and test cases ---------------------------------------------------------------------------------------------
CREATE TABLE T(A NULL);
> exception
CREATE TABLE T(A INT);
> ok
ALTER TABLE T ALTER COLUMN A NULL;
> exception
DROP TABLE T;
> ok
CREATE ROLE TEST_A; CREATE ROLE TEST_A;
> ok > ok
......
create table test (id varchar(36) as random_uuid() primary key);
insert into test() values();
delete from test where id = select id from test;
drop table test;
create table test (id varchar(36) as now() primary key);
insert into test() values();
delete from test where id = select id from test;
drop table test;
SELECT SOME(X>4) FROM SYSTEM_RANGE(1,6); SELECT SOME(X>4) FROM SYSTEM_RANGE(1,6);
> TRUE; > TRUE;
SELECT EVERY(X>4) FROM SYSTEM_RANGE(1,6); SELECT EVERY(X>4) FROM SYSTEM_RANGE(1,6);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论