提交 2493777f authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 caca6aaf
#! /bin/sh #!/bin/sh
if [ -z "$JAVA_HOME" ] ; then if [ -z "$JAVA_HOME" ] ; then
echo "Error: JAVA_HOME is not defined." echo "Error: JAVA_HOME is not defined."
fi fi
if [ ! -f "bin/org/h2/build/Build.class" ] ; then if [ ! -f "bin/org/h2/build/Build.class" ] ; then
if [ ! -d "bin" ] ; then if [ ! -d "bin" ] ; then
md bin mkdir bin
fi fi
javac -sourcepath src/tools -d bin src/tools/org/h2/build/*.java javac -sourcepath src/tools -d bin src/tools/org/h2/build/*.java
fi fi
......
...@@ -943,6 +943,16 @@ Remote SSL/TLS connections are supported using the Java Secure Socket Extension ...@@ -943,6 +943,16 @@ Remote SSL/TLS connections are supported using the Java Secure Socket Extension
(SSLServerSocket / SSLSocket). By default, anonymous SSL is enabled. (SSLServerSocket / SSLSocket). By default, anonymous SSL is enabled.
The default cipher suite is <code>SSL_DH_anon_WITH_RC4_128_MD5</code>. The default cipher suite is <code>SSL_DH_anon_WITH_RC4_128_MD5</code>.
</p> </p>
<p>
To use your own keystore, set the system properties <code>javax.net.ssl.keyStore</code> and
<code>javax.net.ssl.keyStorePassword</code> before starting the H2 server and client.
See also <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CustomizingStores">
Customizing the Default Key and Trust Stores, Store Types, and Store Passwords</a>
for more information.
</p>
<p>
To disable anonymous SSL, set the system property <code>h2.enableAnonymousSSL</code> to false.
</p>
<h3>HTTPS Connections</h3> <h3>HTTPS Connections</h3>
<p> <p>
......
...@@ -3013,6 +3013,7 @@ public class Parser { ...@@ -3013,6 +3013,7 @@ public class Parser {
private Column parseColumnForTable(String columnName) throws SQLException { private Column parseColumnForTable(String columnName) throws SQLException {
Column column; Column column;
boolean isIdentity = false;
if (readIf("IDENTITY") || readIf("SERIAL")) { if (readIf("IDENTITY") || readIf("SERIAL")) {
column = new Column(columnName, Value.LONG); column = new Column(columnName, Value.LONG);
column.setOriginalSQL("IDENTITY"); column.setOriginalSQL("IDENTITY");
...@@ -3028,6 +3029,9 @@ public class Parser { ...@@ -3028,6 +3029,9 @@ public class Parser {
column.setNullable(true); column.setNullable(true);
} }
if (readIf("AS")) { if (readIf("AS")) {
if (isIdentity) {
getSyntaxError();
}
Expression expr = readExpression(); Expression expr = readExpression();
column.setComputed(true, expr); column.setComputed(true, expr);
} else if (readIf("DEFAULT")) { } else if (readIf("DEFAULT")) {
......
...@@ -87,6 +87,12 @@ public class SysProperties { ...@@ -87,6 +87,12 @@ public class SysProperties {
*/ */
public static final String ALLOWED_CLASSES = getStringSetting("h2.allowedClasses", "*"); public static final String ALLOWED_CLASSES = getStringSetting("h2.allowedClasses", "*");
/**
* System property <code>h2.enableAnonymousSSL</code> (default: true).<br />
* Comma separated list of class names or prefixes.
*/
public static final boolean ENABLE_ANONYMOUS_SSL = getBooleanSetting("h2.enableAnonymousSSL", true);
/** /**
* System property <code>h2.bindAddress</code> (default: *).<br /> * System property <code>h2.bindAddress</code> (default: *).<br />
* Comma separated list of class names or prefixes. * Comma separated list of class names or prefixes.
......
...@@ -249,6 +249,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index { ...@@ -249,6 +249,11 @@ public abstract class BaseIndex extends SchemaObjectBase implements Index {
int k1 = rowData.getPos(); int k1 = rowData.getPos();
int k2 = compare.getPos(); int k2 = compare.getPos();
if (k1 == k2) { if (k1 == k2) {
if (database.isMultiVersion()) {
int v1 = rowData.getVersion();
int v2 = compare.getVersion();
return v1 == v2 ? 0 : v1 < v2 ? 1 : -1;
}
return 0; return 0;
} }
return k1 > k2 ? 1 : -1; return k1 > k2 ? 1 : -1;
......
...@@ -165,7 +165,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader { ...@@ -165,7 +165,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
// create a row that only contains the key values // create a row that only contains the key values
setChanged(session); setChanged(session);
Row row = table.getTemplateRow(); Row row = table.getTemplateRow();
row.setPos(r.getPos()); row.setPosAndVersion(r);
for (int i = 0; i < columns.length; i++) { for (int i = 0; i < columns.length; i++) {
Column col = columns[i]; Column col = columns[i];
int idx = col.getColumnId(); int idx = col.getColumnId();
...@@ -189,7 +189,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader { ...@@ -189,7 +189,7 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
SearchRow getSearchRow(Row row) { SearchRow getSearchRow(Row row) {
SearchRow r = table.getTemplateSimpleRow(columns.length == 1); SearchRow r = table.getTemplateSimpleRow(columns.length == 1);
r.setPos(row.getPos()); r.setPosAndVersion(row);
for (int j = 0; j < columns.length; j++) { for (int j = 0; j < columns.length; j++) {
int idx = columns[j].getColumnId(); int idx = columns[j].getColumnId();
r.setValue(idx, row.getValue(idx)); r.setValue(idx, row.getValue(idx));
......
...@@ -142,7 +142,11 @@ public class MultiVersionCursor implements Cursor { ...@@ -142,7 +142,11 @@ public class MultiVersionCursor implements Cursor {
} }
int compare = index.compareRows(deltaRow, baseRow); int compare = index.compareRows(deltaRow, baseRow);
if (compare == 0) { if (compare == 0) {
compare = index.compareKeys(deltaRow, baseRow); // can't use compareKeys because the
// version would be compared as well
int k1 = deltaRow.getPos();
int k2 = baseRow.getPos();
compare = k1 == k2 ? 0 : k1 > k2 ? 1 : -1;
} }
if (compare == 0) { if (compare == 0) {
if (isDeleted) { if (isDeleted) {
...@@ -170,9 +174,6 @@ public class MultiVersionCursor implements Cursor { ...@@ -170,9 +174,6 @@ public class MultiVersionCursor implements Cursor {
needNewBase = true; needNewBase = true;
return true; return true;
} }
if (!isDeleted) {
throw Message.getInternalError();
}
onBase = false; onBase = false;
needNewDelta = true; needNewDelta = true;
return true; return true;
......
...@@ -120,15 +120,17 @@ public class MultiVersionIndex implements Index { ...@@ -120,15 +120,17 @@ public class MultiVersionIndex implements Index {
public boolean needRebuild() { public boolean needRebuild() {
return base.needRebuild(); return base.needRebuild();
} }
private boolean removeIfExists(Session session, Row row) throws SQLException { private boolean removeIfExists(Session session, Row row) throws SQLException {
// maybe it was inserted by the same session just before // maybe it was inserted by the same session just before
Cursor c = delta.find(session, row, row); Cursor c = delta.find(session, row, row);
while (c.next()) { while (c.next()) {
Row r = c.get(); Row r = c.get();
if (r.getPos() == row.getPos()) { if (r.getPos() == row.getPos() && r.getVersion() == row.getVersion()) {
if (r == row || table.getScanIndex(session).compareRows(r, row) == 0) { if (r != row && table.getScanIndex(session).compareRows(r, row) != 0) {
delta.remove(session, row); row.setVersion(r.getVersion() + 1);
} else {
delta.remove(session, r);
return true; return true;
} }
} }
...@@ -146,7 +148,7 @@ public class MultiVersionIndex implements Index { ...@@ -146,7 +148,7 @@ public class MultiVersionIndex implements Index {
} }
} }
} }
public void remove(Session session) throws SQLException { public void remove(Session session) throws SQLException {
synchronized (sync) { synchronized (sync) {
base.remove(session); base.remove(session);
......
...@@ -114,6 +114,7 @@ public class ScanIndex extends BaseIndex { ...@@ -114,6 +114,7 @@ public class ScanIndex extends BaseIndex {
} }
storage.addRecord(session, row, Storage.ALLOCATE_POS); storage.addRecord(session, row, Storage.ALLOCATE_POS);
} else { } else {
// in-memory
if (firstFree == -1) { if (firstFree == -1) {
int key = rows.size(); int key = rows.size();
row.setPos(key); row.setPos(key);
...@@ -171,6 +172,7 @@ public class ScanIndex extends BaseIndex { ...@@ -171,6 +172,7 @@ public class ScanIndex extends BaseIndex {
} }
} }
} else { } else {
// in-memory
Row free = new Row(null, 0); Row free = new Row(null, 0);
free.setPos(firstFree); free.setPos(firstFree);
int key = row.getPos(); int key = row.getPos();
......
...@@ -29,7 +29,7 @@ import org.h2.message.TraceObject; ...@@ -29,7 +29,7 @@ import org.h2.message.TraceObject;
/*## Java 1.6 begin ## /*## Java 1.6 begin ##
import org.h2.message.Message; import org.h2.message.Message;
//## Java 1.4 end ## ## Java 1.6 end ##*/
/** /**
* A data source for H2 database connections. It is a factory for XAConnection * A data source for H2 database connections. It is a factory for XAConnection
......
...@@ -19,11 +19,25 @@ public class Row extends Record implements SearchRow { ...@@ -19,11 +19,25 @@ public class Row extends Record implements SearchRow {
public static final int MEMORY_CALCULATE = -1; public static final int MEMORY_CALCULATE = -1;
private final Value[] data; private final Value[] data;
private final int memory; private final int memory;
private int version;
public Row(Value[] data, int memory) { public Row(Value[] data, int memory) {
this.data = data; this.data = data;
this.memory = memory; this.memory = memory;
} }
public void setPosAndVersion(SearchRow row) {
setPos(row.getPos());
setVersion(row.getVersion());
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Row(Row old) { public Row(Row old) {
this.data = old.data; this.data = old.data;
...@@ -79,6 +93,9 @@ public class Row extends Record implements SearchRow { ...@@ -79,6 +93,9 @@ public class Row extends Record implements SearchRow {
StringBuffer buff = new StringBuffer(data.length * 5); StringBuffer buff = new StringBuffer(data.length * 5);
buff.append("( /* pos:"); buff.append("( /* pos:");
buff.append(getPos()); buff.append(getPos());
if (version != 0) {
buff.append(" v:" + version);
}
if (getDeleted()) { if (getDeleted()) {
buff.append(" deleted"); buff.append(" deleted");
} }
......
...@@ -44,11 +44,12 @@ public class RowList { ...@@ -44,11 +44,12 @@ public class RowList {
} }
private void writeRow(DataPage buff, Row r) throws SQLException { private void writeRow(DataPage buff, Row r) throws SQLException {
buff.checkCapacity(1 + buff.getIntLen() * 6); buff.checkCapacity(1 + buff.getIntLen() * 7);
buff.writeByte((byte) 1); buff.writeByte((byte) 1);
buff.writeInt(r.getMemorySize()); buff.writeInt(r.getMemorySize());
buff.writeInt(r.getColumnCount()); buff.writeInt(r.getColumnCount());
buff.writeInt(r.getPos()); buff.writeInt(r.getPos());
buff.writeInt(r.getVersion());
buff.writeInt(r.getDeleted() ? 1 : 0); buff.writeInt(r.getDeleted() ? 1 : 0);
buff.writeInt(r.getSessionId()); buff.writeInt(r.getSessionId());
buff.writeInt(r.getStorageId()); buff.writeInt(r.getStorageId());
...@@ -143,6 +144,7 @@ public class RowList { ...@@ -143,6 +144,7 @@ public class RowList {
int memory = buff.readInt(); int memory = buff.readInt();
int columnCount = buff.readInt(); int columnCount = buff.readInt();
int pos = buff.readInt(); int pos = buff.readInt();
int version = buff.readInt();
if (readUncached) { if (readUncached) {
pos = 0; pos = 0;
} }
...@@ -170,6 +172,7 @@ public class RowList { ...@@ -170,6 +172,7 @@ public class RowList {
} }
Row row = new Row(values, memory); Row row = new Row(values, memory);
row.setPos(pos); row.setPos(pos);
row.setVersion(version);
row.setDeleted(deleted); row.setDeleted(deleted);
row.setSessionId(sessionId); row.setSessionId(sessionId);
row.setStorageId(storageId); row.setStorageId(storageId);
......
...@@ -14,11 +14,11 @@ import org.h2.value.Value; ...@@ -14,11 +14,11 @@ import org.h2.value.Value;
public interface SearchRow { public interface SearchRow {
/** /**
* Get the position of the row in the data file. * Get the column count.
* *
* @return the position * @return the column count
*/ */
int getPos(); int getColumnCount();
/** /**
* Get the value for the column * Get the value for the column
...@@ -28,13 +28,6 @@ public interface SearchRow { ...@@ -28,13 +28,6 @@ public interface SearchRow {
*/ */
Value getValue(int index); Value getValue(int index);
/**
* Get the column count.
*
* @return the column count
*/
int getColumnCount();
/** /**
* Set the value for given column * Set the value for given column
* *
...@@ -43,6 +36,13 @@ public interface SearchRow { ...@@ -43,6 +36,13 @@ public interface SearchRow {
*/ */
void setValue(int index, Value v); void setValue(int index, Value v);
/**
* Set the position and version to match another row.
*
* @param old the other row.
*/
void setPosAndVersion(SearchRow old);
/** /**
* Set the position (where the row is stored in the data file). * Set the position (where the row is stored in the data file).
* *
...@@ -50,4 +50,18 @@ public interface SearchRow { ...@@ -50,4 +50,18 @@ public interface SearchRow {
*/ */
void setPos(int pos); void setPos(int pos);
/**
* Get the position of the row in the data file.
*
* @return the position
*/
int getPos();
/**
* Get the version of the row.
*
* @return the version
*/
int getVersion();
} }
...@@ -13,6 +13,7 @@ import org.h2.value.Value; ...@@ -13,6 +13,7 @@ import org.h2.value.Value;
public class SimpleRow implements SearchRow { public class SimpleRow implements SearchRow {
private int pos; private int pos;
private int version;
private Value[] data; private Value[] data;
public SimpleRow(Value[] data) { public SimpleRow(Value[] data) {
...@@ -30,6 +31,15 @@ public class SimpleRow implements SearchRow { ...@@ -30,6 +31,15 @@ public class SimpleRow implements SearchRow {
public void setPos(int pos) { public void setPos(int pos) {
this.pos = pos; this.pos = pos;
} }
public void setPosAndVersion(SearchRow row) {
pos = row.getPos();
version = row.getVersion();
}
public int getVersion() {
return version;
}
public void setValue(int i, Value v) { public void setValue(int i, Value v) {
data[i] = v; data[i] = v;
......
...@@ -13,6 +13,7 @@ import org.h2.value.Value; ...@@ -13,6 +13,7 @@ import org.h2.value.Value;
public class SimpleRowValue implements SearchRow { public class SimpleRowValue implements SearchRow {
private int pos; private int pos;
private int version;
private int index; private int index;
private int virtualColumnCount; private int virtualColumnCount;
private Value data; private Value data;
...@@ -20,6 +21,19 @@ public class SimpleRowValue implements SearchRow { ...@@ -20,6 +21,19 @@ public class SimpleRowValue implements SearchRow {
public SimpleRowValue(int columnCount) { public SimpleRowValue(int columnCount) {
this.virtualColumnCount = columnCount; this.virtualColumnCount = columnCount;
} }
public void setPosAndVersion(SearchRow row) {
pos = row.getPos();
version = row.getVersion();
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getColumnCount() { public int getColumnCount() {
return virtualColumnCount; return virtualColumnCount;
......
...@@ -28,6 +28,7 @@ import javax.net.ssl.SSLServerSocketFactory; ...@@ -28,6 +28,7 @@ import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import org.h2.constant.SysProperties;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.util.ByteUtils; import org.h2.util.ByteUtils;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
...@@ -45,8 +46,6 @@ public class SecureSocketFactory { ...@@ -45,8 +46,6 @@ public class SecureSocketFactory {
private static final String KEYSTORE_PASSWORD_KEY = "javax.net.ssl.keyStorePassword"; private static final String KEYSTORE_PASSWORD_KEY = "javax.net.ssl.keyStorePassword";
public static final String KEYSTORE_PASSWORD = "h2pass"; public static final String KEYSTORE_PASSWORD = "h2pass";
// TODO security / SSL: need a way to disable anonymous ssl
private static final boolean ENABLE_ANONYMOUS_SSL = true;
private static SecureSocketFactory factory; private static SecureSocketFactory factory;
private static final String ANONYMOUS_CIPHER_SUITE = "SSL_DH_anon_WITH_RC4_128_MD5"; private static final String ANONYMOUS_CIPHER_SUITE = "SSL_DH_anon_WITH_RC4_128_MD5";
...@@ -67,7 +66,7 @@ public class SecureSocketFactory { ...@@ -67,7 +66,7 @@ public class SecureSocketFactory {
setKeystore(); setKeystore();
SSLSocketFactory f = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocketFactory f = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket secureSocket = (SSLSocket) f.createSocket(address, port); SSLSocket secureSocket = (SSLSocket) f.createSocket(address, port);
if (ENABLE_ANONYMOUS_SSL) { if (SysProperties.ENABLE_ANONYMOUS_SSL) {
String[] list = secureSocket.getEnabledCipherSuites(); String[] list = secureSocket.getEnabledCipherSuites();
list = addAnonymous(list); list = addAnonymous(list);
secureSocket.setEnabledCipherSuites(list); secureSocket.setEnabledCipherSuites(list);
...@@ -89,7 +88,7 @@ public class SecureSocketFactory { ...@@ -89,7 +88,7 @@ public class SecureSocketFactory {
} else { } else {
secureSocket = (SSLServerSocket) f.createServerSocket(port, 0, bindAddress); secureSocket = (SSLServerSocket) f.createServerSocket(port, 0, bindAddress);
} }
if (ENABLE_ANONYMOUS_SSL) { if (SysProperties.ENABLE_ANONYMOUS_SSL) {
String[] list = secureSocket.getEnabledCipherSuites(); String[] list = secureSocket.getEnabledCipherSuites();
list = addAnonymous(list); list = addAnonymous(list);
secureSocket.setEnabledCipherSuites(list); secureSocket.setEnabledCipherSuites(list);
......
...@@ -86,9 +86,9 @@ public class Backup extends Tool { ...@@ -86,9 +86,9 @@ public class Backup extends Tool {
/** /**
* Backs up database files. * Backs up database files.
* *
* @param zipFileName the name of the backup file * @param zipFileName the name of the target backup file (including path)
* @param directory the directory name * @param directory the source directory name
* @param db the database name (null if there is only one database) * @param db the source database name (null if there is only one database)
* @param quiet don't print progress information * @param quiet don't print progress information
* @throws SQLException * @throws SQLException
*/ */
......
...@@ -159,6 +159,17 @@ java org.h2.test.TestAll timer ...@@ -159,6 +159,17 @@ java org.h2.test.TestAll timer
/* /*
Flux
Java Job Scheduler. File Transfer. Workflow. BPM.
http://www.fluxcorp.com/
No database files found > in directory " + for a database called .
Has anyone had difficulty with Open Office Base and UUID type fields
in H2? I think that I may not be able to view table data that has
UUID data in it. Any ideas?
test case for out of memory (try to corrupt the database using out of memory) test case for out of memory (try to corrupt the database using out of memory)
analyzer configuration option for the fulltext search analyzer configuration option for the fulltext search
...@@ -216,11 +227,13 @@ Multi version concurrency (MVCC): when a row was updated, ...@@ -216,11 +227,13 @@ Multi version concurrency (MVCC): when a row was updated,
not committed not committed
Calling SHUTDOWN on one connection and starting a query on Calling SHUTDOWN on one connection and starting a query on
another connection concurrently could result in a Java level deadlock. another connection concurrently could result in a Java level deadlock.
New system property h2.enableAnonymousSSL (default: true) to enable
anonymous SSL connections.
Roadmap: Roadmap:
*/ */
if (args.length > 0) { if (args.length > 0) {
if ("crash".equals(args[0])) { if ("crash".equals(args[0])) {
test.endless = true; test.endless = true;
...@@ -417,7 +430,6 @@ Roadmap: ...@@ -417,7 +430,6 @@ Roadmap:
* Run all tests with the current settings. * Run all tests with the current settings.
*/ */
private void test() throws Exception { private void test() throws Exception {
System.out.println(); System.out.println();
System.out.println("Test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc + " deleteIndex:" + deleteIndex); System.out.println("Test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc + " deleteIndex:" + deleteIndex);
beforeTest(); beforeTest();
......
...@@ -502,7 +502,7 @@ public class TestCases extends TestBase { ...@@ -502,7 +502,7 @@ public class TestCases extends TestBase {
conn.createStatement().execute("INSERT INTO TEST_SEQ(NAME) VALUES('Hi')"); conn.createStatement().execute("INSERT INTO TEST_SEQ(NAME) VALUES('Hi')");
ResultSet rs = conn.createStatement().executeQuery("CALL IDENTITY()"); ResultSet rs = conn.createStatement().executeQuery("CALL IDENTITY()");
rs.next(); rs.next();
check(rs.getInt(1), 1); check(1, rs.getInt(1));
conn.createStatement().execute("SELECT * FROM TEST2"); conn.createStatement().execute("SELECT * FROM TEST2");
conn.createStatement().execute("SELECT * FROM TEST_B"); conn.createStatement().execute("SELECT * FROM TEST_B");
conn.createStatement().execute("ALTER TABLE TEST_B RENAME TO TEST_B2"); conn.createStatement().execute("ALTER TABLE TEST_B RENAME TO TEST_B2");
...@@ -512,7 +512,7 @@ public class TestCases extends TestBase { ...@@ -512,7 +512,7 @@ public class TestCases extends TestBase {
conn.createStatement().execute("INSERT INTO TEST_SEQ(NAME) VALUES('World')"); conn.createStatement().execute("INSERT INTO TEST_SEQ(NAME) VALUES('World')");
rs = conn.createStatement().executeQuery("CALL IDENTITY()"); rs = conn.createStatement().executeQuery("CALL IDENTITY()");
rs.next(); rs.next();
check(rs.getInt(1), 2); check(2, rs.getInt(1));
conn.close(); conn.close();
} }
......
...@@ -85,32 +85,6 @@ public class TestMvcc1 extends TestBase { ...@@ -85,32 +85,6 @@ public class TestMvcc1 extends TestBase {
s2 = c2.createStatement(); s2 = c2.createStatement();
c1.setAutoCommit(false); c1.setAutoCommit(false);
c2.setAutoCommit(false); c2.setAutoCommit(false);
// it should not be possible to drop a table
// when an uncommitted transaction changed something
s1.execute("create table test(id int primary key)");
s1.execute("insert into test values(1)");
try {
s2.execute("drop table test");
error();
} catch (SQLException e) {
// lock timeout expected
checkNotGeneralException(e);
}
c1.rollback();
s2.execute("drop table test");
c2.rollback();
// table scan problem
s1.execute("create table test(id int, name varchar)");
s1.execute("insert into test values(1, 'A'), (2, 'B')");
c1.commit();
test(s1, "select count(*) from test where name<>'C'", "2");
s2.execute("update test set name='B2' where id=2");
test(s1, "select count(*) from test where name<>'C'", "2");
c2.commit();
s2.execute("drop table test");
c2.rollback();
// update same key problem // update same key problem
s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID))"); s1.execute("CREATE TABLE TEST(ID INT, NAME VARCHAR, PRIMARY KEY(ID))");
...@@ -123,7 +97,7 @@ public class TestMvcc1 extends TestBase { ...@@ -123,7 +97,7 @@ public class TestMvcc1 extends TestBase {
s1.execute("DROP TABLE TEST"); s1.execute("DROP TABLE TEST");
c1.commit(); c1.commit();
c2.commit(); c2.commit();
// referential integrity problem // referential integrity problem
s1.execute("create table a (id integer identity not null, code varchar(10) not null, primary key(id))"); s1.execute("create table a (id integer identity not null, code varchar(10) not null, primary key(id))");
s1.execute("create table b (name varchar(100) not null, a integer, primary key(name), foreign key(a) references a(id))"); s1.execute("create table b (name varchar(100) not null, a integer, primary key(name), foreign key(a) references a(id))");
...@@ -139,6 +113,32 @@ public class TestMvcc1 extends TestBase { ...@@ -139,6 +113,32 @@ public class TestMvcc1 extends TestBase {
s1.execute("drop table a, b"); s1.execute("drop table a, b");
c2.commit(); c2.commit();
// it should not be possible to drop a table
// when an uncommitted transaction changed something
s1.execute("create table test(id int primary key)");
s1.execute("insert into test values(1)");
try {
s2.execute("drop table test");
error();
} catch (SQLException e) {
// lock timeout expected
checkNotGeneralException(e);
}
c1.rollback();
s2.execute("drop table test");
c2.rollback();
// table scan problem
s1.execute("create table test(id int, name varchar)");
s1.execute("insert into test values(1, 'A'), (2, 'B')");
c1.commit();
test(s1, "select count(*) from test where name<>'C'", "2");
s2.execute("update test set name='B2' where id=2");
test(s1, "select count(*) from test where name<>'C'", "2");
c2.commit();
s2.execute("drop table test");
c2.rollback();
// select for update should do an exclusive lock, even with mvcc // select for update should do an exclusive lock, even with mvcc
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, 'y')"); s1.execute("insert into test values(1, 'y')");
......
...@@ -17,6 +17,7 @@ import org.h2.test.TestBase; ...@@ -17,6 +17,7 @@ import org.h2.test.TestBase;
public class TestMvcc3 extends TestBase { public class TestMvcc3 extends TestBase {
public void test() throws Exception { public void test() throws Exception {
testSequence();
if (!config.mvcc) { if (!config.mvcc) {
return; return;
} }
...@@ -34,6 +35,32 @@ public class TestMvcc3 extends TestBase { ...@@ -34,6 +35,32 @@ public class TestMvcc3 extends TestBase {
check(1, rs.getInt(1)); check(1, rs.getInt(1));
conn.close(); conn.close();
} }
private void testSequence() throws Exception {
if (config.memory) {
return;
}
deleteDb("mvcc3");
Connection conn;
ResultSet rs;
conn = getConnection("mvcc3");
conn.createStatement().execute("create sequence abc");
conn.close();
conn = getConnection("mvcc3");
rs = conn.createStatement().executeQuery("call abc.nextval");
rs.next();
check(1, rs.getInt(1));
conn.close();
conn = getConnection("mvcc3");
rs = conn.createStatement().executeQuery("call abc.currval");
rs.next();
check(1, rs.getInt(1));
conn.close();
}
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import java.lang.reflect.Method;
import java.sql.Timestamp; import java.sql.Timestamp;
/** /**
...@@ -37,7 +38,43 @@ public class SelfDestructor extends Thread { ...@@ -37,7 +38,43 @@ public class SelfDestructor extends Thread {
} }
} }
String time = new Timestamp(System.currentTimeMillis()).toString(); String time = new Timestamp(System.currentTimeMillis()).toString();
System.out.println(time + " Killing the process after " + minutes + " minutes"); System.out.println(time + " Killing the process after " + minutes + " minute(s)");
try {
int activeCount = Thread.activeCount();
Thread[] threads = new Thread[activeCount + 100];
int len = Thread.enumerate(threads);
for (int i = 0; i < len; i++) {
Thread t = threads[i];
String threadName = "Thread #" + i + ": " + t.getName();
System.out.println(threadName);
}
System.out.flush();
try {
Thread.sleep(1000);
} catch (Exception e) {
// ignore
}
Method stop = Thread.class.getMethod("stop", new Class[]{Throwable.class});
for (int i = 0; i < len; i++) {
Thread t = threads[i];
String threadName = "Thread #" + i + ": " + t.getName();
Error e = new Error(threadName);
if (t != Thread.currentThread()) {
stop.invoke(t, new Object[]{e});
t.interrupt();
}
}
} catch (Throwable t) {
t.printStackTrace();
// ignore
}
try {
Thread.sleep(1000);
} catch (Exception e) {
// ignore
}
System.out.println("Killing the process now");
Runtime.getRuntime().halt(1); Runtime.getRuntime().halt(1);
} }
}; };
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论