提交 f0436942 authored 作者: Thomas Mueller's avatar Thomas Mueller

Cluster: non-admin users could not connect when one of the cluster node was stopped. Issue 206.

上级 632bf2a0
......@@ -10,6 +10,7 @@ import java.text.Collator;
import org.h2.command.Prepared;
import org.h2.compress.Compressor;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Mode;
import org.h2.engine.Session;
......@@ -82,8 +83,13 @@ public class Set extends Prepared {
addOrUpdateSetting(name, null, getIntValue());
break;
case SetTypes.CLUSTER: {
if (Constants.CLUSTERING_ENABLED.equals(stringValue)) {
// this value is used when connecting
// ignore, as the cluster setting is checked later
break;
}
String value = StringUtils.quoteStringSQL(stringValue);
if (!value.equals(database.getCluster()) && !value.equals("''")) {
if (!value.equals(database.getCluster()) && !value.equals(Constants.CLUSTERING_DISABLED)) {
// anybody can disable the cluster
// (if he can't access a cluster node)
session.getUser().checkAdmin();
......
......@@ -81,6 +81,12 @@ public class Constants {
*/
public static final String CLUSTERING_DISABLED = "''";
/**
* The value of the cluster setting if clustering is enabled (the actual
* value is checked later).
*/
public static final String CLUSTERING_ENABLED = "TRUE";
/**
* The database URL used when calling a function if only the column list
* should be returned.
......
......@@ -195,11 +195,13 @@ public class Engine {
}
String clusterDb = database.getCluster();
if (!Constants.CLUSTERING_DISABLED.equals(clusterDb)) {
if (!StringUtils.equals(clusterSession, clusterDb)) {
if (clusterDb.equals(Constants.CLUSTERING_DISABLED)) {
throw DbException.get(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_ALONE);
if (!Constants.CLUSTERING_ENABLED.equals(clusterSession)) {
if (!StringUtils.equals(clusterSession, clusterDb)) {
if (clusterDb.equals(Constants.CLUSTERING_DISABLED)) {
throw DbException.get(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_ALONE);
}
throw DbException.get(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_CLUSTERED_1, clusterDb);
}
throw DbException.get(ErrorCode.CLUSTER_ERROR_DATABASE_RUNS_CLUSTERED_1, clusterDb);
}
}
}
......
......@@ -153,7 +153,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
}
}
private void switchOffAutoCommitIfCluster() {
private void checkClusterDisableAutoCommit(String serverList) {
if (autoCommit && transferList.size() > 1) {
if (switchOffAutoCommit == null) {
switchOffAutoCommit = prepareCommand("SET AUTOCOMMIT FALSE", Integer.MAX_VALUE);
......@@ -162,6 +162,8 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
switchOffAutoCommit.executeUpdate();
// so we need to switch it on
autoCommit = true;
CommandInterface c = prepareCommand("SET CLUSTER " + serverList, Integer.MAX_VALUE);
c.executeUpdate();
cluster = true;
}
}
......@@ -290,7 +292,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
String serverList = null;
if (server.indexOf(',') >= 0) {
serverList = StringUtils.quoteStringSQL(server);
ci.setProperty("CLUSTER", serverList);
ci.setProperty("CLUSTER", Constants.CLUSTERING_ENABLED);
}
autoReconnect = Boolean.valueOf(ci.getProperty("AUTO_RECONNECT", "false")).booleanValue();
// AUTO_SERVER implies AUTO_RECONNECT
......@@ -332,7 +334,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
if (switchOffCluster) {
switchOffCluster();
}
switchOffAutoCommitIfCluster();
checkClusterDisableAutoCommit(serverList);
} catch (DbException e) {
traceSystem.close();
throw e;
......
......@@ -11,6 +11,8 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.Tool;
......@@ -100,15 +102,19 @@ public class CreateCluster extends Tool {
try {
org.h2.Driver.load();
// verify that the database doesn't exist
boolean exists;
// verify that the database doesn't exist,
// or if it exists (an old cluster instance), it is deleted
boolean exists = true;
try {
connTarget = DriverManager.getConnection(urlTarget + ";IFEXISTS=TRUE", user, password);
connTarget = DriverManager.getConnection(urlTarget + ";IFEXISTS=TRUE;CLUSTER=" + Constants.CLUSTERING_ENABLED, user, password);
connTarget.createStatement().execute("DROP ALL OBJECTS DELETE FILES");
exists = false;
connTarget.close();
exists = true;
} catch (SQLException e) {
// database does not exists - ok
exists = false;
if (e.getErrorCode() == ErrorCode.DATABASE_NOT_FOUND_1) {
// database does not exists yet - ok
exists = false;
}
}
if (exists) {
throw new SQLException("Target database must not yet exist. Please delete it first");
......
......@@ -112,6 +112,16 @@ public class TestCluster extends TestBase {
check(connApp, len, "'" + serverList + "'");
n1.stop();
// test non-admin cluster connection if only one server runs
Connection connApp2 = DriverManager.getConnection(urlCluster + ";AUTO_RECONNECT=TRUE", user2, password2);
check(connApp2, len, "''");
connApp2.close();
// test non-admin cluster connection if only one server runs
connApp2 = DriverManager.getConnection(urlCluster + ";AUTO_RECONNECT=TRUE", user2, password2);
check(connApp2, len, "''");
connApp2.close();
n2.stop();
deleteFiles();
}
......@@ -179,6 +189,9 @@ public class TestCluster extends TestBase {
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
check(conn, len, "''");
conn.close();
conn = DriverManager.getConnection("jdbc:h2:tcp://" + serverList + "/test", user, password);
check(conn, len, "''");
conn.close();
// disable the cluster
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:"+port1+"/test;CLUSTER=''", user, password);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论