提交 5a2c152e authored 作者: Thomas Mueller's avatar Thomas Mueller

Linked tables that point to the same database now share the connection.

上级 272423cb
......@@ -49,6 +49,7 @@ import org.h2.table.IndexColumn;
import org.h2.table.MetaTable;
import org.h2.table.Table;
import org.h2.table.TableData;
import org.h2.table.TableLinkConnection;
import org.h2.table.TableView;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Server;
......@@ -160,6 +161,7 @@ public class Database implements DataHandler {
private boolean autoServerMode;
private Object reserveMemory;
private Server server;
private HashMap linkConnections;
public Database(String name, ConnectionInfo ci, String cipher) throws SQLException {
this.compareMode = new CompareMode(null, null, 0);
......@@ -2053,5 +2055,21 @@ public class Database implements DataHandler {
public void freeReserveMemory() {
reserveMemory = null;
}
/**
* Open a new connection or get an existing connection to another database.
*
* @param driver the database driver or null
* @param url the database URL
* @param user the user name
* @param password the password
* @return the connection
*/
public TableLinkConnection getLinkConnection(String driver, String url, String user, String password) throws SQLException {
if (linkConnections == null) {
linkConnections = new HashMap();
}
return TableLinkConnection.open(linkConnections, driver, url, user, password);
}
}
......@@ -67,19 +67,21 @@ public class LinkedIndex extends BaseIndex {
}
buff.append(')');
String sql = buff.toString();
try {
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0, j = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (v != null && v != ValueNull.INSTANCE) {
v.set(prep, j + 1);
j++;
synchronized (link.getConnection()) {
try {
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0, j = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (v != null && v != ValueNull.INSTANCE) {
v.set(prep, j + 1);
j++;
}
}
prep.executeUpdate();
rowCount++;
} catch (SQLException e) {
throw wrapException(sql, e);
}
prep.executeUpdate();
rowCount++;
} catch (SQLException e) {
throw wrapException(sql, e);
}
}
......@@ -114,27 +116,29 @@ public class LinkedIndex extends BaseIndex {
}
buff.insert(0, "SELECT * FROM " + targetTableName + " T");
String sql = buff.toString();
try {
PreparedStatement prep = link.getPreparedStatement(sql);
int j = 0;
for (int i = 0; first != null && i < first.getColumnCount(); i++) {
Value v = first.getValue(i);
if (v != null) {
v.set(prep, j + 1);
j++;
synchronized (link.getConnection()) {
try {
PreparedStatement prep = link.getPreparedStatement(sql);
int j = 0;
for (int i = 0; first != null && i < first.getColumnCount(); i++) {
Value v = first.getValue(i);
if (v != null) {
v.set(prep, j + 1);
j++;
}
}
}
for (int i = 0; last != null && i < last.getColumnCount(); i++) {
Value v = last.getValue(i);
if (v != null) {
v.set(prep, j + 1);
j++;
for (int i = 0; last != null && i < last.getColumnCount(); i++) {
Value v = last.getValue(i);
if (v != null) {
v.set(prep, j + 1);
j++;
}
}
ResultSet rs = prep.executeQuery();
return new LinkedCursor(table, rs, session);
} catch (SQLException e) {
throw wrapException(sql, e);
}
ResultSet rs = prep.executeQuery();
return new LinkedCursor(table, rs, session);
} catch (SQLException e) {
throw wrapException(sql, e);
}
}
......@@ -202,19 +206,21 @@ public class LinkedIndex extends BaseIndex {
}
}
String sql = buff.toString();
try {
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0, j = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (!isNull(v)) {
v.set(prep, j + 1);
j++;
synchronized (link.getConnection()) {
try {
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0, j = 0; i < row.getColumnCount(); i++) {
Value v = row.getValue(i);
if (!isNull(v)) {
v.set(prep, j + 1);
j++;
}
}
int count = prep.executeUpdate();
rowCount -= count;
} catch (SQLException e) {
throw wrapException(sql, e);
}
int count = prep.executeUpdate();
rowCount -= count;
} catch (SQLException e) {
throw wrapException(sql, e);
}
}
......@@ -251,25 +257,27 @@ public class LinkedIndex extends BaseIndex {
}
}
String sql = buff.toString();
try {
int j = 1;
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0; i < newRow.getColumnCount(); i++) {
newRow.getValue(i).set(prep, j);
j++;
}
for (int i = 0; i < oldRow.getColumnCount(); i++) {
Value v = oldRow.getValue(i);
if (!isNull(v)) {
v.set(prep, j);
synchronized (link.getConnection()) {
try {
int j = 1;
PreparedStatement prep = link.getPreparedStatement(sql);
for (int i = 0; i < newRow.getColumnCount(); i++) {
newRow.getValue(i).set(prep, j);
j++;
}
for (int i = 0; i < oldRow.getColumnCount(); i++) {
Value v = oldRow.getValue(i);
if (!isNull(v)) {
v.set(prep, j);
j++;
}
}
int count = prep.executeUpdate();
// this has no effect but at least it allows to debug the update count
rowCount = rowCount + count - count;
} catch (SQLException e) {
throw wrapException(sql, e);
}
int count = prep.executeUpdate();
// this has no effect but at least it allows to debug the update count
rowCount = rowCount + count - count;
} catch (SQLException e) {
throw wrapException(sql, e);
}
}
......
......@@ -6,7 +6,6 @@
*/
package org.h2.table;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
......@@ -40,7 +39,7 @@ import org.h2.value.DataType;
public class TableLink extends Table {
private String driver, url, user, password, originalSchema, originalTable, qualifiedTableName;
private Connection conn;
private TableLinkConnection conn;
private HashMap prepared = new HashMap();
private final ObjectArray indexes = new ObjectArray();
private final boolean emitUpdates;
......@@ -77,8 +76,20 @@ public class TableLink extends Table {
}
private void connect() throws SQLException {
conn = JdbcUtils.getConnection(driver, url, user, password);
DatabaseMetaData meta = conn.getMetaData();
conn = database.getLinkConnection(driver, url, user, password);
synchronized (conn) {
try {
readMetaData();
} catch (SQLException e) {
conn.close();
conn = null;
throw e;
}
}
}
private void readMetaData() throws SQLException {
DatabaseMetaData meta = conn.getConnection().getMetaData();
storesLowerCase = meta.storesLowerCaseIdentifiers();
storesMixedCase = meta.storesMixedCaseIdentifiers();
supportsMixedCaseIdentifiers = meta.supportsMixedCaseIdentifiers();
......@@ -129,7 +140,7 @@ public class TableLink extends Table {
// check if the table is accessible
Statement stat = null;
try {
stat = conn.createStatement();
stat = conn.getConnection().createStatement();
rs = stat.executeQuery("SELECT * FROM " + qualifiedTableName + " T WHERE 1=0");
if (columnList.size() == 0) {
// alternative solution
......@@ -359,7 +370,7 @@ public class TableLink extends Table {
}
PreparedStatement prep = (PreparedStatement) prepared.get(sql);
if (prep == null) {
prep = conn.prepareStatement(sql);
prep = conn.getConnection().prepareStatement(sql);
prepared.put(sql, prep);
}
return prep;
......@@ -399,7 +410,6 @@ public class TableLink extends Table {
database.removeMeta(session, getId());
driver = null;
url = user = password = originalTable = null;
conn = null;
prepared = null;
invalidate();
}
......@@ -457,4 +467,8 @@ public class TableLink extends Table {
this.readOnly = readOnly;
}
public TableLinkConnection getConnection() {
return conn;
}
}
......@@ -195,4 +195,14 @@ public class ObjectUtils {
}
}
/**
* Calculate the hash code of the given object. The object may be null.
*
* @param the object
* @return the hash code, or 0 if the object is null
*/
public static int hashCode(Object o) {
return o == null ? 0 : o.hashCode();
}
}
......@@ -276,8 +276,6 @@ java org.h2.test.TestAll timer
test on linux
main methods for the tests and make that work
TestMVCC:
Concurrent update in table test: another transaction has updated or
deleted the same row when exactly does it occur in other databases
......
......@@ -41,7 +41,7 @@ public abstract class TestBase {
*/
protected TestAll config;
private long start;
protected long start;
/**
* Get the test directory for this test.
......
......@@ -73,6 +73,7 @@ public class TestLinkedTable extends TestBase {
sa.execute("CREATE SCHEMA P");
sa.execute("CREATE TABLE P.TEST(X INT)");
sa.execute("INSERT INTO TEST VALUES(1)");
sa.execute("INSERT INTO P.TEST VALUES(2)");
try {
sb.execute("CREATE LINKED TABLE T(NULL, 'jdbc:h2:mem:one', 'sa', 'sa', 'TEST')");
fail();
......@@ -81,6 +82,8 @@ public class TestLinkedTable extends TestBase {
}
sb.execute("CREATE LINKED TABLE T(NULL, 'jdbc:h2:mem:one', 'sa', 'sa', 'PUBLIC', 'TEST')");
sb.execute("CREATE LINKED TABLE T2(NULL, 'jdbc:h2:mem:one', 'sa', 'sa', 'P', 'TEST')");
assertSingleValue(sb, "SELECT * FROM T", 1);
assertSingleValue(sb, "SELECT * FROM T2", 2);
sa.execute("DROP ALL OBJECTS");
sb.execute("DROP ALL OBJECTS");
ca.close();
......
......@@ -21,7 +21,7 @@ import org.h2.util.JdbcUtils;
*/
public class TestListener extends TestBase implements DatabaseEventListener {
private long last, start;
private long last;
private int lastState = -1;
private String url;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论