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

start to implement row level locks

上级 4908d970
...@@ -176,8 +176,10 @@ public abstract class Command implements CommandInterface { ...@@ -176,8 +176,10 @@ 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) {
session.unlockReadLocks(); if (db.getLockMode() == Constants.LOCK_MODE_READ_COMMITTED) {
session.unlockReadLocks();
}
} }
} }
if (trace.isInfoEnabled()) { if (trace.isInfoEnabled()) {
......
...@@ -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) {
// READ_COMMITTED read locks are acquired but they if (!database.getMultiThreaded() && !database.isMultiVersion()) {
// are released immediately // READ_COMMITTED read locks are acquired but they
// when allowing only one thread, no read locks are // are released immediately
// required // when allowing only one thread, no read locks are
return; // required
} else if (!lockShared.contains(session)) { // row level locks work like read committed
return;
}
}
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);
......
/* /*
* Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License, * Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0 * Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.test; package org.h2.test;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.Reader; import java.io.Reader;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Properties; import java.util.Properties;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.message.TraceSystem; import org.h2.message.TraceSystem;
import org.h2.store.FileLock; import org.h2.store.FileLock;
import org.h2.tools.DeleteDbFiles; import org.h2.tools.DeleteDbFiles;
/** /**
* The base class for all tests. * The base class for all tests.
*/ */
public abstract class TestBase { public abstract class TestBase {
/** /**
* The base directory to write test databases. * The base directory to write test databases.
*/ */
protected static String baseDir = getTestDir(""); protected static String baseDir = getTestDir("");
private static final String BASE_TEST_DIR = "data"; private static final String BASE_TEST_DIR = "data";
/** /**
* The test configuration. * The test configuration.
*/ */
protected TestAll config; protected TestAll config;
private long start; private long start;
/** /**
* Get the test directory for this test. * Get the test directory for this test.
* *
* @param name the directory name suffix * @param name the directory name suffix
*/ */
public static String getTestDir(String name) { public static String getTestDir(String name) {
return BASE_TEST_DIR + "/test" + name; return BASE_TEST_DIR + "/test" + name;
} }
/** /**
* Start the TCP server if enabled in the configuration. * Start the TCP server if enabled in the configuration.
*/ */
protected void startServerIfRequired() throws SQLException { protected void startServerIfRequired() throws SQLException {
config.beforeTest(); config.beforeTest();
} }
/** /**
* Initialize the test configuration. * Initialize the test configuration.
* *
* @param conf the configuration * @param conf the configuration
* @return itself * @return itself
*/ */
public TestBase init(TestAll conf) throws Exception { public TestBase init(TestAll conf) throws Exception {
baseDir = getTestDir(""); baseDir = getTestDir("");
this.config = conf; this.config = conf;
return this; return this;
} }
/** /**
* Run a test case using the given seed value. * Run a test case using the given seed value.
* *
* @param seed the random seed value * @param seed the random seed value
*/ */
public void testCase(int seed) throws Exception { public void testCase(int seed) throws Exception {
// do nothing // do nothing
} }
/** /**
* This method is initializes the test, runs the test by calling the test() * This method is initializes the test, runs the test by calling the test()
* method, and prints status information. It also catches exceptions so that * method, and prints status information. It also catches exceptions so that
* the tests can continue. * the tests can continue.
* *
* @param conf the test configuration * @param conf the test configuration
*/ */
public void runTest(TestAll conf) { public void runTest(TestAll conf) {
try { try {
init(conf); init(conf);
start = System.currentTimeMillis(); start = System.currentTimeMillis();
test(); test();
println(""); println("");
} catch (Exception e) { } catch (Exception e) {
println("FAIL " + e.toString()); println("FAIL " + e.toString());
logError("FAIL " + e.toString(), e); logError("FAIL " + e.toString(), e);
if (config.stopOnError) { if (config.stopOnError) {
throw new Error("ERROR"); throw new Error("ERROR");
} }
} }
} }
/** /**
* Open a database connection in admin mode. The default user name and * Open a database connection in admin mode. The default user name and
* password is used. * password is used.
* *
* @param name the database name * @param name the database name
* @return the connection * @return the connection
*/ */
public Connection getConnection(String name) throws Exception { public Connection getConnection(String name) throws Exception {
return getConnectionInternal(getURL(name, true), getUser(), getPassword()); return getConnectionInternal(getURL(name, true), getUser(), getPassword());
} }
/** /**
* Open a database connection. * Open a database connection.
* *
* @param name the database name * @param name the database name
* @param user the user name to use * @param user the user name to use
* @param password the password to use * @param password the password to use
* @return the connection * @return the connection
*/ */
protected Connection getConnection(String name, String user, String password) throws Exception { protected Connection getConnection(String name, String user, String password) throws Exception {
return getConnectionInternal(getURL(name, false), user, password); return getConnectionInternal(getURL(name, false), user, password);
} }
protected String getPassword() { protected String getPassword() {
return "123"; return "123";
} }
private void deleteIndexFiles(String name) { private void deleteIndexFiles(String name) {
if (name.indexOf(";") > 0) { if (name.indexOf(";") > 0) {
name = name.substring(0, name.indexOf(';')); name = name.substring(0, name.indexOf(';'));
} }
name += ".index.db"; name += ".index.db";
if (new File(name).canWrite()) { if (new File(name).canWrite()) {
new File(name).delete(); new File(name).delete();
} }
} }
/** /**
* Get the database URL for the given database name using the current * Get the database URL for the given database name using the current
* configuration options. * configuration options.
* *
* @param name the database name * @param name the database name
* @param admin true if the current user is an admin * @param admin true if the current user is an admin
* @return the database URL * @return the database URL
*/ */
protected String getURL(String name, boolean admin) { protected String getURL(String name, boolean admin) {
String url; String url;
if (name.startsWith("jdbc:")) { if (name.startsWith("jdbc:")) {
return name; return name;
} }
if (config.memory) { if (config.memory) {
url = "mem:" + name; url = "mem:" + name;
} else { } else {
if (!name.startsWith("memFS:") && !name.startsWith(baseDir + "/")) { if (!name.startsWith("memFS:") && !name.startsWith(baseDir + "/")) {
name = baseDir + "/" + name; name = baseDir + "/" + name;
} }
if (config.deleteIndex) { if (config.deleteIndex) {
deleteIndexFiles(name); deleteIndexFiles(name);
} }
if (config.networked) { if (config.networked) {
if (config.ssl) { if (config.ssl) {
url = "ssl://localhost:9192/" + name; url = "ssl://localhost:9192/" + name;
} else { } else {
url = "tcp://localhost:9192/" + name; url = "tcp://localhost:9192/" + name;
} }
} else { } else {
url = name; url = name;
} }
if (config.traceSystemOut) { if (config.traceSystemOut) {
url += ";TRACE_LEVEL_SYSTEM_OUT=2"; url += ";TRACE_LEVEL_SYSTEM_OUT=2";
} }
if (config.traceLevelFile > 0 && admin) { if (config.traceLevelFile > 0 && admin) {
url += ";TRACE_LEVEL_FILE=" + config.traceLevelFile; url += ";TRACE_LEVEL_FILE=" + config.traceLevelFile;
} }
} }
if (config.throttle > 0) { if (config.throttle > 0) {
url += ";THROTTLE=" + config.throttle; url += ";THROTTLE=" + config.throttle;
} }
if (config.textStorage) { if (config.textStorage) {
url += ";STORAGE=TEXT"; url += ";STORAGE=TEXT";
} }
url += ";LOCK_TIMEOUT=50"; if (url.indexOf("LOCK_TIMEOUT=") < 0) {
if (admin) { url += ";LOCK_TIMEOUT=50";
url += ";LOG=" + config.logMode; }
} if (admin) {
if (config.smallLog && admin) { url += ";LOG=" + config.logMode;
url += ";MAX_LOG_SIZE=1"; }
} if (config.smallLog && admin) {
if (config.diskUndo && admin) { url += ";MAX_LOG_SIZE=1";
url += ";MAX_MEMORY_UNDO=3"; }
} if (config.diskUndo && admin) {
if (config.big && admin) { url += ";MAX_MEMORY_UNDO=3";
// force operations to disk }
url += ";MAX_OPERATION_MEMORY=1"; if (config.big && admin) {
} // force operations to disk
if (config.mvcc) { url += ";MAX_OPERATION_MEMORY=1";
url += ";MVCC=TRUE"; }
} if (config.mvcc && url.indexOf("MVCC=") < 0) {
if (config.cache2Q) { url += ";MVCC=TRUE";
url += ";CACHE_TYPE=TQ"; }
} if (config.cache2Q) {
if (config.diskResult && admin) { url += ";CACHE_TYPE=TQ";
url += ";MAX_MEMORY_ROWS=100;CACHE_SIZE=0"; }
} if (config.diskResult && admin) {
return "jdbc:h2:" + url; url += ";MAX_MEMORY_ROWS=100;CACHE_SIZE=0";
} }
return "jdbc:h2:" + url;
private Connection getConnectionInternal(String url, String user, String password) throws Exception { }
Class.forName("org.h2.Driver");
// url += ";DEFAULT_TABLE_TYPE=1"; private Connection getConnectionInternal(String url, String user, String password) throws Exception {
// Class.forName("org.hsqldb.jdbcDriver"); Class.forName("org.h2.Driver");
// return DriverManager.getConnection("jdbc:hsqldb:" + name, "sa", ""); // url += ";DEFAULT_TABLE_TYPE=1";
Connection conn; // Class.forName("org.hsqldb.jdbcDriver");
if (config.cipher != null) { // return DriverManager.getConnection("jdbc:hsqldb:" + name, "sa", "");
url += ";cipher=" + config.cipher; Connection conn;
password = "filePassword " + password; if (config.cipher != null) {
Properties info = new Properties(); url += ";cipher=" + config.cipher;
info.setProperty("user", user); password = "filePassword " + password;
info.setProperty("password", password); Properties info = new Properties();
// a bug in the PostgreSQL driver: throws a NullPointerException if we do this info.setProperty("user", user);
// info.put("password", password.toCharArray()); info.setProperty("password", password);
conn = DriverManager.getConnection(url, info); // a bug in the PostgreSQL driver: throws a NullPointerException if we do this
} else { // info.put("password", password.toCharArray());
conn = DriverManager.getConnection(url, user, password); conn = DriverManager.getConnection(url, info);
} } else {
return conn; conn = DriverManager.getConnection(url, user, password);
} }
return conn;
/** }
* Get the small or the big value depending on the configuration.
* /**
* @param small the value to return if the current test mode is 'small' * Get the small or the big value depending on the configuration.
* @param big the value to return if the current test mode is 'big' *
* @return small or big, depending on the configuration * @param small the value to return if the current test mode is 'small'
*/ * @param big the value to return if the current test mode is 'big'
protected int getSize(int small, int big) { * @return small or big, depending on the configuration
return config.endless ? Integer.MAX_VALUE : config.big ? big : small; */
} protected int getSize(int small, int big) {
return config.endless ? Integer.MAX_VALUE : config.big ? big : small;
protected String getUser() { }
return "sa";
} protected String getUser() {
return "sa";
/** }
* Write a message to system out if trace is enabled.
* /**
* @param x the value to write * Write a message to system out if trace is enabled.
*/ *
protected void trace(int x) { * @param x the value to write
trace("" + x); */
} protected void trace(int x) {
trace("" + x);
/** }
* Write a message to system out if trace is enabled.
* /**
* @param s the message to write * Write a message to system out if trace is enabled.
*/ *
public void trace(String s) { * @param s the message to write
if (config.traceTest) { */
println(s); public void trace(String s) {
} if (config.traceTest) {
} println(s);
}
/** }
* Print how much memory is currently used.
*/ /**
protected void traceMemory() { * Print how much memory is currently used.
if (config.traceTest) { */
trace("mem=" + getMemoryUsed()); protected void traceMemory() {
} if (config.traceTest) {
} trace("mem=" + getMemoryUsed());
}
/** }
* Print the currently used memory, the message and the given time in
* milliseconds. /**
* * Print the currently used memory, the message and the given time in
* @param s the message * milliseconds.
* @param time the time in millis *
*/ * @param s the message
public void printTimeMemory(String s, long time) { * @param time the time in millis
if (config.big) { */
println(getMemoryUsed() + " MB: " + s + " ms: " + time); public void printTimeMemory(String s, long time) {
} if (config.big) {
} println(getMemoryUsed() + " MB: " + s + " ms: " + time);
}
/** }
* Get the number of megabytes heap memory in use.
* /**
* @return the used megabytes * Get the number of megabytes heap memory in use.
*/ *
public static int getMemoryUsed() { * @return the used megabytes
Runtime rt = Runtime.getRuntime(); */
long memory = Long.MAX_VALUE; public static int getMemoryUsed() {
for (int i = 0; i < 8; i++) { Runtime rt = Runtime.getRuntime();
rt.gc(); long memory = Long.MAX_VALUE;
long memNow = rt.totalMemory() - rt.freeMemory(); for (int i = 0; i < 8; i++) {
if (memNow >= memory) { rt.gc();
break; long memNow = rt.totalMemory() - rt.freeMemory();
} if (memNow >= memory) {
memory = memNow; break;
} }
int mb = (int) (memory / 1024 / 1024); memory = memNow;
return mb; }
} int mb = (int) (memory / 1024 / 1024);
return mb;
/** }
* Called if the test reached a point that was not expected.
* /**
* @throws Exception always throws an exception * Called if the test reached a point that was not expected.
*/ *
protected void fail() throws Exception { * @throws Exception always throws an exception
fail("Unexpected success"); */
} protected void fail() throws Exception {
fail("Unexpected success");
/** }
* Called if the test reached a point that was not expected.
* /**
* @param string the error message * Called if the test reached a point that was not expected.
* @throws Exception always throws an exception *
*/ * @param string the error message
protected void fail(String string) throws Exception { * @throws Exception always throws an exception
println(string); */
throw new Exception(string); protected void fail(String string) throws Exception {
} println(string);
throw new Exception(string);
/** }
* Log an error message.
* /**
* @param s the message * Log an error message.
* @param e the exception *
*/ * @param s the message
public static void logError(String s, Throwable e) { * @param e the exception
if (e == null) { */
e = new Exception(s); public static void logError(String s, Throwable e) {
} if (e == null) {
System.out.println("ERROR: " + s + " " + e.toString() + " ------------------------------"); e = new Exception(s);
e.printStackTrace(); }
try { System.out.println("ERROR: " + s + " " + e.toString() + " ------------------------------");
TraceSystem ts = new TraceSystem(null, false); e.printStackTrace();
FileLock lock = new FileLock(ts, 1000); try {
lock.lock("error.lock", false); TraceSystem ts = new TraceSystem(null, false);
FileWriter fw = new FileWriter("ERROR.txt", true); FileLock lock = new FileLock(ts, 1000);
PrintWriter pw = new PrintWriter(fw); lock.lock("error.lock", false);
e.printStackTrace(pw); FileWriter fw = new FileWriter("ERROR.txt", true);
pw.close(); PrintWriter pw = new PrintWriter(fw);
fw.close(); e.printStackTrace(pw);
lock.unlock(); pw.close();
} catch (Throwable t) { fw.close();
t.printStackTrace(); lock.unlock();
} } catch (Throwable t) {
} t.printStackTrace();
}
/** }
* Print a message to system out.
* /**
* @param s the message * Print a message to system out.
*/ *
protected void println(String s) { * @param s the message
long time = System.currentTimeMillis() - start; */
printlnWithTime(time, getClass().getName() + " " + s); protected void println(String s) {
} long time = System.currentTimeMillis() - start;
printlnWithTime(time, getClass().getName() + " " + s);
/** }
* Print a message, prepended with the specified time in milliseconds.
* /**
* @param time the milliseconds * Print a message, prepended with the specified time in milliseconds.
* @param s the message *
*/ * @param time the milliseconds
static void printlnWithTime(long time, String s) { * @param s the message
String t = "0000000000" + time; */
t = t.substring(t.length() - 6); static void printlnWithTime(long time, String s) {
System.out.println(t + " " + s); String t = "0000000000" + time;
} t = t.substring(t.length() - 6);
System.out.println(t + " " + s);
/** }
* Print the current time and a message to system out.
* /**
* @param s the message * Print the current time and a message to system out.
*/ *
protected void printTime(String s) { * @param s the message
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); */
println(dateFormat.format(new java.util.Date()) + " " + s); protected void printTime(String s) {
} SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
println(dateFormat.format(new java.util.Date()) + " " + s);
/** }
* Delete all database files for this database.
* /**
* @param name the database name * Delete all database files for this database.
*/ *
protected void deleteDb(String name) throws Exception { * @param name the database name
DeleteDbFiles.execute(baseDir, name, true); */
} protected void deleteDb(String name) throws Exception {
DeleteDbFiles.execute(baseDir, name, true);
/** }
* Delete all database files for a database.
* /**
* @param dir the directory where the database files are located * Delete all database files for a database.
* @param name the database name *
*/ * @param dir the directory where the database files are located
protected void deleteDb(String dir, String name) throws Exception { * @param name the database name
DeleteDbFiles.execute(dir, name, true); */
} protected void deleteDb(String dir, String name) throws Exception {
DeleteDbFiles.execute(dir, name, true);
/** }
* This method will be called by the test framework.
* /**
* @throws Exception if an exception in the test occurs * This method will be called by the test framework.
*/ *
public abstract void test() throws Exception; * @throws Exception if an exception in the test occurs
*/
/** public abstract void test() throws Exception;
* Check if two values are equal, and if not throw an exception.
* /**
* @param message the message to print in case of error * Check if two values are equal, and if not throw an exception.
* @param expected the expected value *
* @param actual the actual value * @param message the message to print in case of error
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
public void assertEquals(String message, int expected, int actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Expected: " + expected + " actual: " + actual + " message: " + message); public void assertEquals(String message, int expected, int actual) throws Exception {
} if (expected != actual) {
} fail("Expected: " + expected + " actual: " + actual + " message: " + message);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
public void assertEquals(int expected, int actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Expected: " + expected + " actual: " + actual); public void assertEquals(int expected, int actual) throws Exception {
} if (expected != actual) {
} fail("Expected: " + expected + " actual: " + actual);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(byte[] expected, byte[] actual) throws Exception { * @throws Exception if the values are not equal
assertTrue(expected.length == actual.length); */
for (int i = 0; i < expected.length; i++) { protected void assertEquals(byte[] expected, byte[] actual) throws Exception {
if (expected[i] != actual[i]) { assertTrue(expected.length == actual.length);
fail("Expected[" + i + "]: a=" + (int) expected[i] + " actual=" + (int) actual[i]); for (int i = 0; i < expected.length; i++) {
} if (expected[i] != actual[i]) {
} fail("Expected[" + i + "]: a=" + (int) expected[i] + " actual=" + (int) actual[i]);
} }
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(String expected, String actual) throws Exception { * @throws Exception if the values are not equal
if (expected == null && actual == null) { */
return; protected void assertEquals(String expected, String actual) throws Exception {
} else if (expected == null || actual == null) { if (expected == null && actual == null) {
fail("Expected: " + expected + " Actual: " + actual); return;
} } else if (expected == null || actual == null) {
if (!expected.equals(actual)) { fail("Expected: " + expected + " Actual: " + actual);
for (int i = 0; i < expected.length(); i++) { }
String s = expected.substring(0, i); if (!expected.equals(actual)) {
if (!actual.startsWith(s)) { for (int i = 0; i < expected.length(); i++) {
expected = expected.substring(0, i) + "<*>" + expected.substring(i); String s = expected.substring(0, i);
break; if (!actual.startsWith(s)) {
} expected = expected.substring(0, i) + "<*>" + expected.substring(i);
} break;
int al = expected.length(); }
int bl = actual.length(); }
if (al > 100) { int al = expected.length();
expected = expected.substring(0, 400); int bl = actual.length();
} if (al > 100) {
if (bl > 100) { expected = expected.substring(0, 400);
actual = actual.substring(0, 400); }
} if (bl > 100) {
fail("Expected: " + expected + " (" + al + ") actual: " + actual + " (" + bl + ")"); actual = actual.substring(0, 400);
} }
} fail("Expected: " + expected + " (" + al + ") actual: " + actual + " (" + bl + ")");
}
/** }
* Check if the first value is larger or equal than the second value, and if
* not throw an exception. /**
* * Check if the first value is larger or equal than the second value, and if
* @param a the first value * not throw an exception.
* @param b the second value (must be smaller than the first value) *
* @throws Exception if the first value is smaller * @param a the first value
*/ * @param b the second value (must be smaller than the first value)
protected void assertSmaller(long a, long b) throws Exception { * @throws Exception if the first value is smaller
if (a >= b) { */
fail("a: " + a + " is not smaller than b: " + b); protected void assertSmaller(long a, long b) throws Exception {
} if (a >= b) {
} fail("a: " + a + " is not smaller than b: " + b);
}
/** }
* Check that a result contains the given substring.
* /**
* @param result the result value * Check that a result contains the given substring.
* @param contains the term that should appear in the result *
* @throws Exception if the term was not found * @param result the result value
*/ * @param contains the term that should appear in the result
protected void assertContains(String result, String contains) throws Exception { * @throws Exception if the term was not found
if (result.indexOf(contains) < 0) { */
fail(result + " does not contain: " + contains); protected void assertContains(String result, String contains) throws Exception {
} if (result.indexOf(contains) < 0) {
} fail(result + " does not contain: " + contains);
}
/** }
* Check that a text starts with the expected characters..
* /**
* @param text the text * Check that a text starts with the expected characters..
* @param expectedStart the expected prefix *
* @throws Exception if the text does not start with the expected characters * @param text the text
*/ * @param expectedStart the expected prefix
protected void assertStartsWith(String text, String expectedStart) throws Exception { * @throws Exception if the text does not start with the expected characters
if (!text.startsWith(expectedStart)) { */
fail(text + " does not start with: " + expectedStart); protected void assertStartsWith(String text, String expectedStart) throws Exception {
} if (!text.startsWith(expectedStart)) {
} fail(text + " does not start with: " + expectedStart);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(long expected, long actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Expected: " + expected + " actual: " + actual); protected void assertEquals(long expected, long actual) throws Exception {
} if (expected != actual) {
} fail("Expected: " + expected + " actual: " + actual);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(double expected, double actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Expected: " + expected + " actual: " + actual); protected void assertEquals(double expected, double actual) throws Exception {
} if (expected != actual) {
} fail("Expected: " + expected + " actual: " + actual);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(float expected, float actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Expected: " + expected + " actual: " + actual); protected void assertEquals(float expected, float actual) throws Exception {
} if (expected != actual) {
} fail("Expected: " + expected + " actual: " + actual);
}
/** }
* Check if two values are equal, and if not throw an exception.
* /**
* @param expected the expected value * Check if two values are equal, and if not throw an exception.
* @param actual the actual value *
* @throws Exception if the values are not equal * @param expected the expected value
*/ * @param actual the actual value
protected void assertEquals(boolean expected, boolean actual) throws Exception { * @throws Exception if the values are not equal
if (expected != actual) { */
fail("Boolean expected: " + expected + " actual: " + actual); protected void assertEquals(boolean expected, boolean actual) throws Exception {
} if (expected != actual) {
} fail("Boolean expected: " + expected + " actual: " + actual);
}
/** }
* Check that the passed boolean is true.
* /**
* @param condition the condition * Check that the passed boolean is true.
* @throws Exception if the condition is false *
*/ * @param condition the condition
protected void assertTrue(boolean condition) throws Exception { * @throws Exception if the condition is false
assertTrue("Expected: true got: false", condition); */
} protected void assertTrue(boolean condition) throws Exception {
assertTrue("Expected: true got: false", condition);
/** }
* Check that the passed boolean is true.
* /**
* @param message the message to print if the condition is false * Check that the passed boolean is true.
* @param condition the condition *
* @throws Exception if the condition is false * @param message the message to print if the condition is false
*/ * @param condition the condition
protected void assertTrue(String message, boolean condition) throws Exception { * @throws Exception if the condition is false
if (!condition) { */
fail(message); protected void assertTrue(String message, boolean condition) throws Exception {
} if (!condition) {
} fail(message);
}
/** }
* Check that the passed boolean is false.
* /**
* @param value the condition * Check that the passed boolean is false.
* @throws Exception if the condition is true *
*/ * @param value the condition
protected void assertFalse(boolean value) throws Exception { * @throws Exception if the condition is true
assertFalse("Expected: false got: true", value); */
} protected void assertFalse(boolean value) throws Exception {
assertFalse("Expected: false got: true", value);
/** }
* Check that the passed boolean is false.
* /**
* @param message the message to print if the condition is false * Check that the passed boolean is false.
* @param value the condition *
* @throws Exception if the condition is true * @param message the message to print if the condition is false
*/ * @param value the condition
protected void assertFalse(String message, boolean value) throws Exception { * @throws Exception if the condition is true
if (value) { */
fail(message); protected void assertFalse(String message, boolean value) throws Exception {
} if (value) {
} fail(message);
}
/** }
* Check that the result set row count matches.
* /**
* @param rs the result set * Check that the result set row count matches.
* @param expected the number of expected rows *
* @throws Exception if a different number of rows have been found * @param rs the result set
*/ * @param expected the number of expected rows
protected void assertResultRowCount(ResultSet rs, int expected) throws Exception { * @throws Exception if a different number of rows have been found
int i = 0; */
while (rs.next()) { protected void assertResultRowCount(ResultSet rs, int expected) throws Exception {
i++; int i = 0;
} while (rs.next()) {
assertEquals(i, expected); i++;
} }
assertEquals(i, expected);
/** }
* Check that the result set of a query is exactly this value.
* /**
* @param stat the statement * Check that the result set of a query is exactly this value.
* @param sql the SQL statement to execute *
* @param expected the expected result value * @param stat the statement
* @throws Exception if a different result value was returned * @param sql the SQL statement to execute
*/ * @param expected the expected result value
protected void assertSingleValue(Statement stat, String sql, int expected) throws Exception { * @throws Exception if a different result value was returned
ResultSet rs = stat.executeQuery(sql); */
assertTrue(rs.next()); protected void assertSingleValue(Statement stat, String sql, int expected) throws Exception {
assertEquals(expected, rs.getInt(1)); ResultSet rs = stat.executeQuery(sql);
assertFalse(rs.next()); assertTrue(rs.next());
} assertEquals(expected, rs.getInt(1));
assertFalse(rs.next());
/** }
* Check if the result set meta data is correct.
* /**
* @param rs the result set * Check that the result set of a query is exactly this value.
* @param columnCount the expected column count *
* @param labels the expected column labels * @param stat the statement
* @param datatypes the expected data types * @param sql the SQL statement to execute
* @param precision the expected precisions * @param expected the expected result value
* @param scale the expected scales * @throws Exception if a different result value was returned
*/ */
protected void assertResultSetMeta(ResultSet rs, int columnCount, String[] labels, int[] datatypes, int[] precision, protected void assertResult(Statement stat, String sql, String expected) throws Exception {
int[] scale) throws Exception { ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData meta = rs.getMetaData(); if (rs.next()) {
int cc = meta.getColumnCount(); String actual = rs.getString(1);
if (cc != columnCount) { assertEquals(expected, actual);
fail("result set contains " + cc + " columns not " + columnCount); } else {
} assertEquals(null, expected);
for (int i = 0; i < columnCount; i++) { }
if (labels != null) { }
String l = meta.getColumnLabel(i + 1);
if (!labels[i].equals(l)) { /**
fail("column label " + i + " is " + l + " not " + labels[i]); * Check if the result set meta data is correct.
} *
} * @param rs the result set
if (datatypes != null) { * @param columnCount the expected column count
int t = meta.getColumnType(i + 1); * @param labels the expected column labels
if (datatypes[i] != t) { * @param datatypes the expected data types
fail("column datatype " + i + " is " + t + " not " + datatypes[i] + " (prec=" * @param precision the expected precisions
+ meta.getPrecision(i + 1) + " scale=" + meta.getScale(i + 1) + ")"); * @param scale the expected scales
} */
String typeName = meta.getColumnTypeName(i + 1); protected void assertResultSetMeta(ResultSet rs, int columnCount, String[] labels, int[] datatypes, int[] precision,
String className = meta.getColumnClassName(i + 1); int[] scale) throws Exception {
switch (t) { ResultSetMetaData meta = rs.getMetaData();
case Types.INTEGER: int cc = meta.getColumnCount();
assertEquals(typeName, "INTEGER"); if (cc != columnCount) {
assertEquals(className, "java.lang.Integer"); fail("result set contains " + cc + " columns not " + columnCount);
break; }
case Types.VARCHAR: for (int i = 0; i < columnCount; i++) {
assertEquals(typeName, "VARCHAR"); if (labels != null) {
assertEquals(className, "java.lang.String"); String l = meta.getColumnLabel(i + 1);
break; if (!labels[i].equals(l)) {
case Types.SMALLINT: fail("column label " + i + " is " + l + " not " + labels[i]);
assertEquals(typeName, "SMALLINT"); }
assertEquals(className, "java.lang.Short"); }
break; if (datatypes != null) {
case Types.TIMESTAMP: int t = meta.getColumnType(i + 1);
assertEquals(typeName, "TIMESTAMP"); if (datatypes[i] != t) {
assertEquals(className, "java.sql.Timestamp"); fail("column datatype " + i + " is " + t + " not " + datatypes[i] + " (prec="
break; + meta.getPrecision(i + 1) + " scale=" + meta.getScale(i + 1) + ")");
case Types.DECIMAL: }
assertEquals(typeName, "DECIMAL"); String typeName = meta.getColumnTypeName(i + 1);
assertEquals(className, "java.math.BigDecimal"); String className = meta.getColumnClassName(i + 1);
break; switch (t) {
default: case Types.INTEGER:
} assertEquals(typeName, "INTEGER");
} assertEquals(className, "java.lang.Integer");
if (precision != null) { break;
int p = meta.getPrecision(i + 1); case Types.VARCHAR:
if (precision[i] != p) { assertEquals(typeName, "VARCHAR");
fail("column precision " + i + " is " + p + " not " + precision[i]); assertEquals(className, "java.lang.String");
} break;
} case Types.SMALLINT:
if (scale != null) { assertEquals(typeName, "SMALLINT");
int s = meta.getScale(i + 1); assertEquals(className, "java.lang.Short");
if (scale[i] != s) { break;
fail("column scale " + i + " is " + s + " not " + scale[i]); case Types.TIMESTAMP:
} assertEquals(typeName, "TIMESTAMP");
} assertEquals(className, "java.sql.Timestamp");
break;
} case Types.DECIMAL:
} assertEquals(typeName, "DECIMAL");
assertEquals(className, "java.math.BigDecimal");
/** break;
* Check if a result set contains the expected data. default:
* The sort order is significant }
* }
* @param rs the result set if (precision != null) {
* @param data the expected data int p = meta.getPrecision(i + 1);
* @throws Exception if there is a mismatch if (precision[i] != p) {
*/ fail("column precision " + i + " is " + p + " not " + precision[i]);
protected void assertResultSetOrdered(ResultSet rs, String[][] data) throws Exception { }
assertResultSet(true, rs, data); }
} if (scale != null) {
int s = meta.getScale(i + 1);
/** if (scale[i] != s) {
* Check if a result set contains the expected data. fail("column scale " + i + " is " + s + " not " + scale[i]);
* The sort order is not significant }
* }
* @param rs the result set
* @param data the expected data }
* @throws Exception if there is a mismatch }
*/
// void assertResultSetUnordered(ResultSet rs, String[][] data) /**
// throws Exception { * Check if a result set contains the expected data.
// assertResultSet(false, rs, data); * The sort order is significant
// } *
* @param rs the result set
/** * @param data the expected data
* Check if a result set contains the expected data. * @throws Exception if there is a mismatch
* */
* @param ordered if the sort order is significant protected void assertResultSetOrdered(ResultSet rs, String[][] data) throws Exception {
* @param rs the result set assertResultSet(true, rs, data);
* @param data the expected data }
* @throws Exception if there is a mismatch
*/ /**
private void assertResultSet(boolean ordered, ResultSet rs, String[][] data) throws Exception { * Check if a result set contains the expected data.
int len = rs.getMetaData().getColumnCount(); * The sort order is not significant
int rows = data.length; *
if (rows == 0) { * @param rs the result set
// special case: no rows * @param data the expected data
if (rs.next()) { * @throws Exception if there is a mismatch
fail("testResultSet expected rowCount:" + rows + " got:0"); */
} // void assertResultSetUnordered(ResultSet rs, String[][] data)
} // throws Exception {
int len2 = data[0].length; // assertResultSet(false, rs, data);
if (len < len2) { // }
fail("testResultSet expected columnCount:" + len2 + " got:" + len);
} /**
for (int i = 0; i < rows; i++) { * Check if a result set contains the expected data.
if (!rs.next()) { *
fail("testResultSet expected rowCount:" + rows + " got:" + i); * @param ordered if the sort order is significant
} * @param rs the result set
String[] row = getData(rs, len); * @param data the expected data
if (ordered) { * @throws Exception if there is a mismatch
String[] good = data[i]; */
if (!testRow(good, row, good.length)) { private void assertResultSet(boolean ordered, ResultSet rs, String[][] data) throws Exception {
fail("testResultSet row not equal, got:\n" + formatRow(row) + "\n" + formatRow(good)); int len = rs.getMetaData().getColumnCount();
} int rows = data.length;
} else { if (rows == 0) {
boolean found = false; // special case: no rows
for (int j = 0; j < rows; j++) { if (rs.next()) {
String[] good = data[i]; fail("testResultSet expected rowCount:" + rows + " got:0");
if (testRow(good, row, good.length)) { }
found = true; }
break; int len2 = data[0].length;
} if (len < len2) {
} fail("testResultSet expected columnCount:" + len2 + " got:" + len);
if (!found) { }
fail("testResultSet no match for row:" + formatRow(row)); for (int i = 0; i < rows; i++) {
} if (!rs.next()) {
} fail("testResultSet expected rowCount:" + rows + " got:" + i);
} }
if (rs.next()) { String[] row = getData(rs, len);
String[] row = getData(rs, len); if (ordered) {
fail("testResultSet expected rowcount:" + rows + " got:>=" + (rows + 1) + " data:" + formatRow(row)); String[] good = data[i];
} if (!testRow(good, row, good.length)) {
} fail("testResultSet row not equal, got:\n" + formatRow(row) + "\n" + formatRow(good));
}
private boolean testRow(String[] a, String[] b, int len) { } else {
for (int i = 0; i < len; i++) { boolean found = false;
String sa = a[i]; for (int j = 0; j < rows; j++) {
String sb = b[i]; String[] good = data[i];
if (sa == null || sb == null) { if (testRow(good, row, good.length)) {
if (sa != sb) { found = true;
return false; break;
} }
} else { }
if (!sa.equals(sb)) { if (!found) {
return false; fail("testResultSet no match for row:" + formatRow(row));
} }
} }
} }
return true; if (rs.next()) {
} String[] row = getData(rs, len);
fail("testResultSet expected rowcount:" + rows + " got:>=" + (rows + 1) + " data:" + formatRow(row));
private String[] getData(ResultSet rs, int len) throws SQLException { }
String[] data = new String[len]; }
for (int i = 0; i < len; i++) {
data[i] = rs.getString(i + 1); private boolean testRow(String[] a, String[] b, int len) {
// just check if it works for (int i = 0; i < len; i++) {
rs.getObject(i + 1); String sa = a[i];
} String sb = b[i];
return data; if (sa == null || sb == null) {
} if (sa != sb) {
return false;
private String formatRow(String[] row) { }
String sb = ""; } else {
for (int i = 0; i < row.length; i++) { if (!sa.equals(sb)) {
sb += "{" + row[i] + "}"; return false;
} }
return "{" + sb + "}"; }
} }
return true;
/** }
* Simulate a database crash. This method will also close the database
* files, but the files are in a state as the power was switched off. It private String[] getData(ResultSet rs, int len) throws SQLException {
* doesn't throw an exception. String[] data = new String[len];
* for (int i = 0; i < len; i++) {
* @param conn the database connection data[i] = rs.getString(i + 1);
*/ // just check if it works
protected void crash(Connection conn) throws Exception { rs.getObject(i + 1);
((JdbcConnection) conn).setPowerOffCount(1); }
try { return data;
conn.createStatement().execute("SET WRITE_DELAY 0"); }
conn.createStatement().execute("CREATE TABLE TEST_A(ID INT)");
fail("should be crashed already"); private String formatRow(String[] row) {
} catch (SQLException e) { String sb = "";
// expected for (int i = 0; i < row.length; i++) {
} sb += "{" + row[i] + "}";
try { }
conn.close(); return "{" + sb + "}";
} catch (SQLException e) { }
// ignore
} /**
} * Simulate a database crash. This method will also close the database
* files, but the files are in a state as the power was switched off. It
/** * doesn't throw an exception.
* Read a string from the reader. This method reads until end of file. *
* * @param conn the database connection
* @param reader the reader */
* @return the string read protected void crash(Connection conn) throws Exception {
*/ ((JdbcConnection) conn).setPowerOffCount(1);
protected String readString(Reader reader) throws Exception { try {
if (reader == null) { conn.createStatement().execute("SET WRITE_DELAY 0");
return null; conn.createStatement().execute("CREATE TABLE TEST_A(ID INT)");
} fail("should be crashed already");
StringBuffer buffer = new StringBuffer(); } catch (SQLException e) {
try { // expected
while (true) { }
int c = reader.read(); try {
if (c == -1) { conn.close();
break; } catch (SQLException e) {
} // ignore
buffer.append((char) c); }
} }
return buffer.toString();
} catch (Exception e) { /**
assertTrue(false); * Read a string from the reader. This method reads until end of file.
return null; *
} * @param reader the reader
} * @return the string read
*/
/** protected String readString(Reader reader) throws Exception {
* Check that a given exception is not an unexpected 'general error' if (reader == null) {
* exception. return null;
* }
* @param e the error StringBuffer buffer = new StringBuffer();
*/ try {
protected void assertKnownException(SQLException e) throws Exception { while (true) {
assertKnownException("", e); int c = reader.read();
} if (c == -1) {
break;
/** }
* Check that a given exception is not an unexpected 'general error' buffer.append((char) c);
* exception. }
* return buffer.toString();
* @param message the message } catch (Exception e) {
* @param e the exception assertTrue(false);
*/ return null;
protected void assertKnownException(String message, SQLException e) throws Exception { }
if (e != null && e.getSQLState().startsWith("HY000")) { }
TestBase.logError("Unexpected General error " + message, e);
} /**
} * Check that a given exception is not an unexpected 'general error'
* exception.
/** *
* Check if two values are equal, and if not throw an exception. * @param e the error
* */
* @param expected the expected value protected void assertKnownException(SQLException e) throws Exception {
* @param actual the actual value assertKnownException("", e);
* @throws Exception if the values are not equal }
*/
protected void assertEquals(Integer expected, Integer actual) throws Exception { /**
if (expected == null || actual == null) { * Check that a given exception is not an unexpected 'general error'
assertTrue(expected == actual); * exception.
} else { *
assertEquals(expected.intValue(), actual.intValue()); * @param message the message
} * @param e the exception
} */
protected void assertKnownException(String message, SQLException e) throws Exception {
/** if (e != null && e.getSQLState().startsWith("HY000")) {
* Check if two databases contain the same met data. TestBase.logError("Unexpected General error " + message, e);
* }
* @param stat1 the connection to the first database }
* @param stat2 the connection to the second database
* @throws Exception if the database don't match /**
*/ * Check if two values are equal, and if not throw an exception.
protected void assertEqualDatabases(Statement stat1, Statement stat2) throws Exception { *
ResultSet rs1 = stat1.executeQuery("SCRIPT NOPASSWORDS"); * @param expected the expected value
ResultSet rs2 = stat2.executeQuery("SCRIPT NOPASSWORDS"); * @param actual the actual value
ArrayList list1 = new ArrayList(); * @throws Exception if the values are not equal
ArrayList list2 = new ArrayList(); */
while (rs1.next()) { protected void assertEquals(Integer expected, Integer actual) throws Exception {
assertTrue(rs2.next()); if (expected == null || actual == null) {
String s1 = rs1.getString(1); assertTrue(expected == actual);
list1.add(s1); } else {
String s2 = rs2.getString(1); assertEquals(expected.intValue(), actual.intValue());
list2.add(s2); }
} }
for (int i = 0; i < list1.size(); i++) {
String s = (String) list1.get(i); /**
if (!list2.remove(s)) { * Check if two databases contain the same met data.
fail("not found: " + s); *
} * @param stat1 the connection to the first database
} * @param stat2 the connection to the second database
assertEquals(list2.size(), 0); * @throws Exception if the database don't match
assertFalse(rs2.next()); */
} protected void assertEqualDatabases(Statement stat1, Statement stat2) throws Exception {
ResultSet rs1 = stat1.executeQuery("SCRIPT NOPASSWORDS");
} ResultSet rs2 = stat2.executeQuery("SCRIPT NOPASSWORDS");
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
while (rs1.next()) {
assertTrue(rs2.next());
String s1 = rs1.getString(1);
list1.add(s1);
String s2 = rs2.getString(1);
list2.add(s2);
}
for (int i = 0; i < list1.size(); i++) {
String s = (String) list1.get(i);
if (!list2.remove(s)) {
fail("not found: " + s);
}
}
assertEquals(list2.size(), 0);
assertFalse(rs2.next());
}
}
...@@ -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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论