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

--no commit message

--no commit message
上级 488ecc5e
......@@ -64,10 +64,11 @@ public abstract class Command implements CommandInterface {
startTime = System.currentTimeMillis();
Database database = session.getDatabase();
Object sync = database.getMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled();
synchronized (sync) {
try {
database.checkPowerOff();
session.setCurrentCommand(this);
session.setCurrentCommand(this, startTime);
return query(maxrows);
} catch (Throwable e) {
SQLException s = Message.convert(e);
......@@ -92,7 +93,7 @@ public abstract class Command implements CommandInterface {
}
private void stop() throws SQLException {
session.setCurrentCommand(null);
session.setCurrentCommand(null, 0);
if (!isTransactional()) {
session.commit(true);
} else if (session.getAutoCommit()) {
......@@ -115,9 +116,10 @@ public abstract class Command implements CommandInterface {
startTime = System.currentTimeMillis();
Database database = session.getDatabase();
Object sync = database.getMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled();
synchronized (sync) {
int rollback = session.getLogId();
session.setCurrentCommand(this);
session.setCurrentCommand(this, startTime);
try {
database.checkPowerOff();
return update();
......
......@@ -3656,6 +3656,12 @@ public class Parser {
Set command = new Set(session, SetTypes.MVCC);
command.setInt(value ? 1 : 0);
return command;
} else if (readIf("EXCLUSIVE")) {
readIfEqualOrTo();
boolean value = readBooleanSetting();
Set command = new Set(session, SetTypes.EXCLUSIVE);
command.setInt(value ? 1 : 0);
return command;
} else if (readIf("IGNORECASE")) {
readIfEqualOrTo();
boolean value = readBooleanSetting();
......
......@@ -94,20 +94,17 @@ public class SelectUnion extends Query {
}
switch (unionType) {
case UNION:
case EXCEPT:
left.setDistinct(true);
right.setDistinct(true);
result.setDistinct();
break;
case UNION_ALL:
break;
case EXCEPT:
result.setDistinct();
// fall through
case INTERSECT: {
case INTERSECT:
left.setDistinct(true);
right.setDistinct(true);
break;
}
default:
throw Message.getInternalError("type=" + unionType);
}
......
......@@ -274,6 +274,12 @@ public class Set extends Prepared {
database.setMaxOperationMemory(value);
break;
}
case SetTypes.EXCLUSIVE: {
session.getUser().checkAdmin();
int value = getIntValue();
database.setExclusiveSession(value == 1 ? session : null);
break;
}
default:
throw Message.getInternalError("type="+type);
}
......
......@@ -20,10 +20,10 @@ public class SetTypes {
public static final int LOG = 19, THROTTLE = 20, MAX_MEMORY_UNDO = 21, MAX_LENGTH_INPLACE_LOB = 22;
public static final int COMPRESS_LOB = 23, ALLOW_LITERALS = 24, MULTI_THREADED = 25, SCHEMA = 26;
public static final int OPTIMIZE_REUSE_RESULTS = 27, SCHEMA_SEARCH_PATH = 28, UNDO_LOG = 29;
public static final int REFERENTIAL_INTEGRITY = 30, MVCC = 31, MAX_OPERATION_MEMORY = 32;
public static final int REFERENTIAL_INTEGRITY = 30, MVCC = 31, MAX_OPERATION_MEMORY = 32, EXCLUSIVE = 33;
private static ObjectArray types = new ObjectArray();
static {
setType(IGNORECASE, "IGNORECASE");
setType(MAX_LOG_SIZE, "MAX_LOG_SIZE");
......@@ -57,6 +57,7 @@ public class SetTypes {
setType(REFERENTIAL_INTEGRITY, "REFERENTIAL_INTEGRITY");
setType(MVCC, "MVCC");
setType(MAX_OPERATION_MEMORY, "MAX_OPERATION_MEMORY");
setType(EXCLUSIVE, "EXCLUSIVE");
}
private static void setType(int type, String name) {
......
......@@ -315,6 +315,7 @@ public class ErrorCode {
public static final int AGGREGATE_NOT_FOUND_1 = 90132;
public static final int CANNOT_CHANGE_SETTING_WHEN_OPEN_1 = 90133;
public static final int ACCESS_DENIED_TO_CLASS_1 = 90134;
public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135;
/**
* INTERNAL
......
......@@ -7,9 +7,11 @@ package org.h2.engine;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener;
......@@ -85,7 +87,8 @@ public class Database implements DataHandler {
private final HashMap userDataTypes = new HashMap();
private final HashMap aggregates = new HashMap();
private final HashMap comments = new HashMap();
private final HashSet sessions = new HashSet();
private final Set sessions = Collections.synchronizedSet(new HashSet());
private Session exclusiveSession;
private final BitField objectIds = new BitField();
private final Object lobSyncObject = new Object();
......@@ -772,7 +775,10 @@ public class Database implements DataHandler {
return getUser(name, Message.getSQLException(ErrorCode.USER_NOT_FOUND_1, name));
}
public synchronized Session createSession(User user) {
public synchronized Session createSession(User user) throws SQLException {
if (exclusiveSession != null) {
throw Message.getSQLException(ErrorCode.DATABASE_IS_IN_EXCLUSIVE_MODE);
}
Session session = new Session(this, user, ++nextSessionId);
sessions.add(session);
traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName);
......@@ -785,6 +791,9 @@ public class Database implements DataHandler {
public synchronized void removeSession(Session session) throws SQLException {
if (session != null) {
if (exclusiveSession == session) {
exclusiveSession = null;
}
sessions.remove(session);
if (session != systemSession) {
traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId());
......@@ -1032,7 +1041,7 @@ public class Database implements DataHandler {
return log;
}
public synchronized Session[] getSessions() {
public Session[] getSessions() {
Session[] list = new Session[sessions.size()];
sessions.toArray(list);
return list;
......@@ -1624,4 +1633,12 @@ public class Database implements DataHandler {
return maxOperationMemory;
}
public Session getExclusiveSession() {
return exclusiveSession;
}
public void setExclusiveSession(Session session) {
this.exclusiveSession = session;
}
}
......@@ -73,7 +73,8 @@ public class Session implements SessionInterface {
private String currentTransactionName;
private boolean isClosed;
private boolean rollbackMode;
private long loginTime = System.currentTimeMillis();
private long sessionStart = System.currentTimeMillis();
private long currentCommandStart;
public Session() {
}
......@@ -498,8 +499,9 @@ public class Session implements SessionInterface {
}
}
public void setCurrentCommand(Command command) {
public void setCurrentCommand(Command command, long startTime) {
this.currentCommand = command;
this.currentCommandStart = startTime;
}
public void checkCancelled() throws SQLException {
......@@ -508,9 +510,12 @@ public class Session implements SessionInterface {
}
}
public String getCurrentCommand() {
Command c = currentCommand;
return c == null ? null : c.toString();
public Command getCurrentCommand() {
return currentCommand;
}
public long getCurrentCommandStart() {
return currentCommandStart;
}
public boolean getAllowLiterals() {
......@@ -609,8 +614,8 @@ public class Session implements SessionInterface {
return rollbackMode;
}
public long getLoginTime() {
return loginTime;
public long getSessionStart() {
return sessionStart;
}
public Table[] getLocks() {
......@@ -621,4 +626,18 @@ public class Session implements SessionInterface {
}
}
public void waitIfExclusiveModeEnabled() {
while (true) {
Session exclusive = database.getExclusiveSession();
if (exclusive == null || exclusive == this) {
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// ignore
}
}
}
}
......@@ -57,8 +57,6 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
head = (BtreeHead) rec;
}
if (head != null && head.getConsistent()) {
int testing;
// setRoot((BtreePage) storage.getRecord(session, head.getRootPosition()));
needRebuild = false;
rowCount = table.getRowCount(session);
} else {
......
......@@ -155,6 +155,7 @@
90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied
90135=The database is open in exclusive mode; can not open additional connections
HY000=General error\: {0}
HY004=Unknown data type\: {0}
HYC00=Feature not supported
......
......@@ -856,6 +856,19 @@ Admin rights are required to execute this command.
SET DEFAULT_TABLE_TYPE MEMORY
"
"Commands (Other)","SET EXCLUSIVE","
SET EXCLUSIVE {TRUE | FALSE}
","
Switched the database to exclusive mode and back. In exclusive mode, new connections are rejected,
and operations by other connections are paused until the exclusive mode is disabled.
Only the connection that set the exclusive mode can disable it. When the connection is closed,
it is automatically disabled.
This setting is not persistent.
Admin rights are required to execute this command.
","
SET EXCLUSIVE TRUE
"
"Commands (Other)","SET IGNORECASE","
SET IGNORECASE {TRUE|FALSE}
","
......@@ -2559,6 +2572,18 @@ Returns true if auto commit is switched on for this session.
AUTOCOMMIT()
"
"Functions (System)","CANCEL_SESSION","
CANCEL_SESSION(sessionInt): boolean
","
Cancels the currently executing statement of another session.
The method only works if the multithreaded kernel is enabled (see SET MULTI_THREADED).
Returns true if the statement was cancelled, false if the session is closed
or no statement is currently executing.
Admin rights are required to execute this command.
","
CANCEL_STATEMENT(3)
"
"Functions (System)","CASEWHEN Function","
CASEWHEN(boolean, aValue, bValue): value
","
......
......@@ -333,6 +333,7 @@ public class FtpControl extends Thread {
} else if ("XRMD".equals(command)) {
processRemoveDir(param);
}
break;
default:
break;
}
......
......@@ -114,6 +114,7 @@ public class WebServer implements Service {
private ShutdownHandler shutdownHandler;
private Thread listenerThread;
private boolean ifExists;
private boolean allowScript;
byte[] getFile(String file) throws IOException {
trace("getFile <" + file + ">");
......@@ -196,6 +197,8 @@ public class WebServer implements Service {
ssl = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-webAllowOthers".equals(a)) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-webScript".equals(a)) {
allowScript = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-baseDir".equals(a)) {
String baseDir = args[++i];
SysProperties.setBaseDir(baseDir);
......@@ -508,4 +511,8 @@ public class WebServer implements Service {
this.shutdownHandler = shutdownHandler;
}
public boolean getAllowScript() {
return allowScript;
}
}
......@@ -5,13 +5,20 @@
package org.h2.server.web;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.Socket;
import java.security.SecureClassLoader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
......@@ -40,12 +47,12 @@ import org.h2.engine.Constants;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.TraceSystem;
import org.h2.tools.SimpleResultSet;
import org.h2.util.ObjectUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils;
import org.h2.util.NetUtils;
import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.util.ScriptReader;
import org.h2.util.StringUtils;
......@@ -1018,7 +1025,17 @@ class WebThread extends Thread implements DatabaseEventListener {
try {
Connection conn = session.getConnection();
String result;
if ("@AUTOCOMMIT TRUE".equals(sql)) {
if (sql.startsWith("@JAVA")) {
if (server.getAllowScript()) {
try {
result = executeJava(sql.substring("@JAVA".length()));
} catch (Throwable t) {
result = getStackTrace(0, t);
}
} else {
result = "Executing Java code is not allowed, use command line parameters -webScript true";
}
} else if ("@AUTOCOMMIT TRUE".equals(sql)) {
conn.setAutoCommit(true);
result = "${text.result.autoCommitOn}";
} else if ("@AUTOCOMMIT FALSE".equals(sql)) {
......@@ -1068,6 +1085,94 @@ class WebThread extends Thread implements DatabaseEventListener {
return "result.jsp";
}
static class DynamicClassLoader extends SecureClassLoader {
private String name;
private byte[] data;
private Class clazz;
DynamicClassLoader(String name, byte[] data) throws MalformedURLException {
super(DynamicClassLoader.class.getClassLoader());
this.name = name;
this.data = data;
}
public Class loadClass(String className) throws ClassNotFoundException {
return findClass(className);
}
public Class findClass(String className) throws ClassNotFoundException {
if (className.equals(name)) {
if (clazz == null) {
clazz = defineClass(className, data, 0, data.length);
}
return clazz;
}
try {
return findSystemClass(className);
} catch (Exception e) {
}
return super.findClass(className);
}
}
private String executeJava(String code) throws Exception {
File javaFile = new File("Java.java");
File classFile = new File("Java.class");
try {
PrintWriter out = new PrintWriter(new FileWriter(javaFile));
classFile.delete();
int endImport = code.indexOf("@CODE");
String importCode = "import java.util.*; import java.math.*; import java.sql.*;";
if (endImport >= 0) {
importCode = code.substring(0, endImport);
code = code.substring("@CODE".length() + endImport);
}
out.println(importCode);
out.println("public class Java { public static Object run() throws Throwable {" + code + "}}");
out.close();
Process p = Runtime.getRuntime().exec("javac Java.java");
InputStream processIn = p.getInputStream();
InputStream processErrorIn = p.getErrorStream();
StringBuffer buff = new StringBuffer();
while (true) {
int c = processIn.read();
if (c == -1) {
break;
}
buff.append((char) c);
}
while (true) {
int c = processErrorIn.read();
if (c == -1) {
break;
}
buff.append((char) c);
}
String error = buff.toString().trim();
if (error.length() > 0) {
throw new Exception("Error compiling: " + error.toString());
}
byte[] data = new byte[(int) classFile.length()];
DataInputStream in = new DataInputStream(new FileInputStream(classFile));
in.readFully(data);
in.close();
DynamicClassLoader cl = new DynamicClassLoader("Java", data);
Class clazz = cl.loadClass("Java");
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
Method m = methods[i];
if (m.getName().equals("run")) {
return "" + m.invoke(null, new Object[0]);
}
}
return null;
} finally {
javaFile.delete();
classFile.delete();
}
}
private String editResult() {
ResultSet rs = session.result;
int row = Integer.parseInt(attributes.getProperty("row"));
......@@ -1083,7 +1188,7 @@ class WebThread extends Thread implements DatabaseEventListener {
}
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
String x = attributes.getProperty("r" + row + "c" + (i + 1));
rs.updateString(i + 1, x);
rs.updateString(i + 1, unescapeData(x));
}
if (insert) {
rs.insertRow();
......@@ -1611,7 +1716,7 @@ class WebThread extends Thread implements DatabaseEventListener {
buff.append(PageParser.escapeHtml(meta.getColumnLabel(i + 1)));
buff.append("</td>");
buff.append("<td>");
buff.append(PageParser.escapeHtml(rs.getString(i + 1)));
buff.append(escapeData(rs.getString(i + 1)));
buff.append("</td></tr>");
}
}
......@@ -1645,7 +1750,7 @@ class WebThread extends Thread implements DatabaseEventListener {
}
for (int i = 0; i < columns; i++) {
buff.append("<td>");
buff.append(PageParser.escapeHtml(rs.getString(i + 1)));
buff.append(escapeData(rs.getString(i + 1)));
buff.append("</td>");
}
buff.append("</tr>");
......@@ -1713,6 +1818,26 @@ class WebThread extends Thread implements DatabaseEventListener {
return "index.do";
}
private String escapeData(String d) {
if (d == null) {
return "<i>null</i>";
} else if (d.startsWith("null")) {
return "<div style='display: none'>=</div>" + PageParser.escapeHtml(d);
}
return PageParser.escapeHtml(d);
}
private String unescapeData(String d) {
if (d.endsWith("null")) {
if (d.equals("null")) {
return null;
} else if (d.startsWith("=")) {
return d.substring(1);
}
}
return d;
}
private String settingRemove() {
String setting = attributes.getProperty("name", "");
server.removeSetting(setting);
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
*/
addEvent(window, "load", initSort);
function addEvent(elm, evType, fn, useCapture) {
......@@ -26,7 +26,7 @@ function initSort() {
}
var tables = document.getElementsByTagName("table");
for (var i=0; i<tables.length; i++) {
table = tables[i];
table = tables[i];
if (table.rows && table.rows.length > 0) {
var header = table.rows[0];
for(var j=0;j<header.cells.length;j++) {
......@@ -45,8 +45,8 @@ function editRow(row, session, write, undo) {
for(i=1; i<table.rows.length; i++) {
var cell = table.rows[i].cells[0];
if(i == y) {
var edit = '<img width=16 height=16 src="ico_ok.gif" onclick="javascript:editing.op.value=\'1\';editing.row.value=\''+row+'\';editing.submit()" onmouseover = "this.className =\'icon_hover\'" onmouseout = "this.className=\'icon\'" class="icon" alt="'+write+'" title="'+write+'" border="1"/>';
var undo = '<img width=16 height=16 src="ico_undo.gif" onclick="javascript:editing.op.value=\'3\';editing.row.value=\''+row+'\';editing.submit()" onmouseover = "this.className =\'icon_hover\'" onmouseout = "this.className=\'icon\'" class="icon" alt="'+undo+'" title="'+undo+'" border="1"/>';
var edit = '<img width=16 height=16 src="ico_ok.gif" onclick="editOk('+row+')" onmouseover = "this.className =\'icon_hover\'" onmouseout = "this.className=\'icon\'" class="icon" alt="'+write+'" title="'+write+'" border="1"/>';
var undo = '<img width=16 height=16 src="ico_undo.gif" onclick="editCancel('+row+')" onmouseover = "this.className =\'icon_hover\'" onmouseout = "this.className=\'icon\'" class="icon" alt="'+undo+'" title="'+undo+'" border="1"/>';
cell.innerHTML = edit + undo;
} else {
cell.innerHTML = '';
......@@ -56,10 +56,39 @@ function editRow(row, session, write, undo) {
for(i=1; i<cells.length; i++) {
var cell = cells[i];
var text = getInnerText(cell);
cell.innerHTML = '<input type="text" name="r'+row+'c' + i + '" value="'+text+'" size="' + (text.length+5) + '"/>';
cell.innerHTML = '<input type="text" name="r'+row+'c' + i + '" value="'+text+'" size="' + (text.length+5) + '" onkeydown="return editKeyDown(' + row + ', this, event)" />';
}
}
function editCancel(row) {
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='3';
editing.submit();
}
function editOk(row) {
var editing = document.getElementById('editing');
editing.row.value = row;
editing.op.value='1';
editing.submit();
}
function editKeyDown(row, object, event) {
var key=event.keyCode? event.keyCode : event.charCode;
if(key == 46 && event.ctrlKey) {
// ctrl + delete
object.value = 'null';
return false;
} else if(key == 13) {
editOk(row);
return false;
} else if(key == 27) {
editCancel(row);
return false;
}
}
function getInnerText(el) {
if (typeof el == "string") return el;
if (typeof el == "undefined") { return el };
......
......@@ -16,6 +16,7 @@ import java.sql.Timestamp;
import java.text.Collator;
import java.util.Locale;
import org.h2.command.Command;
import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintCheck;
......@@ -434,8 +435,9 @@ public class MetaTable extends Table {
cols = createColumns(new String[]{
"ID INT",
"USER_NAME",
"CURRENT_STATEMENT",
"LOGIN_TIME",
"SESSION_START",
"STATEMENT",
"STATEMENT_START"
});
break;
}
......@@ -707,6 +709,7 @@ public class MetaTable extends Table {
}
}
add(rows, new String[] { "MVCC", database.isMultiVersion() ? "TRUE" : "FALSE" });
add(rows, new String[] { "EXCLUSIVE", database.getExclusiveSession() == null ? "FALSE" : "TRUE" });
add(rows, new String[] { "MODE", database.getMode().getName() });
add(rows, new String[] { "MULTI_THREADED", database.getMultiThreaded() ? "1" : "0"});
DiskFile dataFile = database.getDataFile();
......@@ -1205,11 +1208,13 @@ public class MetaTable extends Table {
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
if (admin || s == session) {
Command command = s.getCurrentCommand();
add(rows, new String[] {
"" + s.getId(), // ID
s.getUser().getName(), // USER_NAME
s.getCurrentCommand(), // CURRENT_COMMAND
new Timestamp(s.getLoginTime()).toString(), // LOGIN_TIME
new Timestamp(s.getSessionStart()).toString(), // SESSION_START
command == null ? null : command.toString(), // STATEMENT
new Timestamp(s.getCurrentCommandStart()).toString() // STATEMENT_START
});
}
}
......
......@@ -28,12 +28,12 @@ import org.h2.util.StartBrowser;
* This tool can be used to start various database servers (listeners).
*/
public class Server implements Runnable, ShutdownHandler {
private Service service;
private static final int EXIT_ERROR = 1;
private Server web, tcp, pg, ftp;
private ShutdownHandler shutdownHandler;
private void showUsage(String a, PrintStream out) {
if (a != null) {
out.println("Unknown option: " + a);
......@@ -53,30 +53,30 @@ public class Server implements Runnable, ShutdownHandler {
out.println("-tcp (start the TCP Server)");
out.println("-tcpAllowOthers {true|false}");
out.println("-tcpPort <port> (default: " + TcpServer.DEFAULT_PORT+")");
out.println("-tcpSSL {true|false}");
out.println("-tcpSSL {true|false}");
out.println("-tcpPassword {password} (the password for shutting down a TCP Server)");
out.println("-tcpShutdown {url} (shutdown the TCP Server, URL example: tcp://localhost:9094)");
out.println("-tcpShutdownForce {true|false} (don't wait for other connections to close)");
out.println();
out.println("-pg (start the PG Server)");
out.println("-pgAllowOthers {true|false}");
out.println("-pgAllowOthers {true|false}");
out.println("-pgPort <port> (default: " + PgServer.DEFAULT_PORT+")");
out.println();
out.println("-ftp (start the FTP Server)");
out.println("-ftpPort <port> (default: " + Constants.DEFAULT_FTP_PORT+")");
out.println("-ftpDir <directory> (default: " + FtpServer.DEFAULT_ROOT+", use jdbc:... to access a database)");
out.println("-ftpDir <directory> (default: " + FtpServer.DEFAULT_ROOT+", use jdbc:... to access a database)");
out.println("-ftpRead <readUserName> (default: " + FtpServer.DEFAULT_READ+")");
out.println("-ftpWrite <writeUserName> (default: " + FtpServer.DEFAULT_WRITE+")");
out.println("-ftpWritePassword <password> (default: " + FtpServer.DEFAULT_WRITE_PASSWORD+")");
out.println("-ftpWritePassword <password> (default: " + FtpServer.DEFAULT_WRITE_PASSWORD+")");
out.println();
out.println("-log {true|false} (enable or disable logging, for all servers)");
out.println("-baseDir <directory> (sets the base directory for H2 databases, for all servers)");
out.println("-ifExists {true|false} (only existing databases may be opened, for all servers)");
}
public Server() {
}
/**
* The command line interface for this tool.
* The options must be split into strings like this: "-baseDir", "/temp/data",...
......@@ -114,7 +114,7 @@ public class Server implements Runnable, ShutdownHandler {
* </li><li>-ftpWrite {writeUserName}
* </li><li>-ftpWritePassword {password}
* </li></ul>
*
*
* @param args the command line arguments
* @throws SQLException
*/
......@@ -150,6 +150,8 @@ public class Server implements Runnable, ShutdownHandler {
i++;
} else if ("-webPort".equals(a)) {
i++;
} else if ("-webScript".equals(a)) {
i++;
} else if ("-webSSL".equals(a)) {
i++;
} else {
......@@ -267,10 +269,10 @@ public class Server implements Runnable, ShutdownHandler {
// ignore (status is displayed)
e.printStackTrace();
exitCode = EXIT_ERROR;
}
}
out.println(web.getStatus());
// start browser anyway (even if the server is already running)
// because some people don't look at the output,
// start browser anyway (even if the server is already running)
// because some people don't look at the output,
// but are wondering why nothing happens
if (browserStart) {
StartBrowser.openURL(web.getURL());
......@@ -289,22 +291,22 @@ public class Server implements Runnable, ShutdownHandler {
}
return exitCode;
}
/**
* Shutdown a TCP server. If force is set to false, the server will not allow new connections,
* but not kill existing connections, instead it will stop if the last connection is closed.
* but not kill existing connections, instead it will stop if the last connection is closed.
* If force is set to true, existing connections are killed.
* After calling the method with force=false, it is not possible to call it again with
* force=true because new connections are not allowed.
* Example:
* <pre>Server.shutdownTcpServer("tcp://localhost:9094", password, true);</pre>
*
*
* @param url example: tcp://localhost:9094
* @param password the password to use ("" for no password)
* @param force the shutdown (don't wait)
* @throws ClassNotFoundException
* @throws SQLException
*/
* @throws SQLException
*/
public static void shutdownTcpServer(String url, String password, boolean force) throws SQLException {
int port = Constants.DEFAULT_SERVER_PORT;
int idx = url.indexOf(':', "jdbc:h2:".length());
......@@ -376,7 +378,7 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new web server, but does not start it yet.
* Example:
* <pre>Server server = Server.createWebServer(new String[]{"-log", "true"}).start();</pre>
*
*
* @param args
* @return the server
*/
......@@ -391,7 +393,7 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new ftp server, but does not start it yet.
* Example:
* <pre>Server server = Server.createFtpServer(new String[]{"-log", "true"}).start();</pre>
*
*
* @param args
* @return the server
*/
......@@ -403,26 +405,26 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new TCP server, but does not start it yet.
* Example:
* <pre>Server server = Server.createTcpServer(new String[]{"-tcpAllowOthers", "true"}).start();</pre>
*
*
* @param args
* @return the server
*/
public static Server createTcpServer(String[] args) throws SQLException {
return new Server(new TcpServer(), args);
}
/**
* Create a new PG server, but does not start it yet.
* Example:
* <pre>Server server = Server.createPgServer(new String[]{"-pgAllowOthers", "true"}).start();</pre>
*
*
* @param args
* @return the server
*/
public static Server createPgServer(String[] args) throws SQLException {
return new Server(new PgServer(), args);
}
/**
* Tries to start the server.
* @return the server if successful
......@@ -473,7 +475,7 @@ public class Server implements Runnable, ShutdownHandler {
/**
* Checks if the server is running.
*
*
* @return if the server is running
*/
public boolean isRunning() {
......@@ -486,7 +488,7 @@ public class Server implements Runnable, ShutdownHandler {
public void stop() {
service.stop();
}
/**
* Gets the URL of this server.
* @return the url
......@@ -514,7 +516,7 @@ public class Server implements Runnable, ShutdownHandler {
TraceSystem.traceThrowable(e);
}
}
/**
* INTERNAL
*/
......@@ -524,7 +526,7 @@ public class Server implements Runnable, ShutdownHandler {
/**
* INTERNAL
*/
*/
public void shutdown() {
if (shutdownHandler != null) {
shutdownHandler.shutdown();
......
......@@ -40,6 +40,7 @@ import org.h2.test.db.TestSQLInjection;
import org.h2.test.db.TestScript;
import org.h2.test.db.TestScriptSimple;
import org.h2.test.db.TestSequence;
import org.h2.test.db.TestSessionsLocks;
import org.h2.test.db.TestSpaceReuse;
import org.h2.test.db.TestSpeed;
import org.h2.test.db.TestTempTables;
......@@ -151,8 +152,15 @@ java org.h2.test.TestAll timer
/*
write simple test for
NFORMATION_SCHEMA.SESSIONS and LOCKS
test & document exclusive mode
test exlclusive mode (inform_sch.settings table, disallow new connections, delay operations by other,
disable when close session, disable
translate error code 90135
C:\temp\test\db
......@@ -576,6 +584,7 @@ Features of H2
new TestRights().runTest(this);
new TestRunscript().runTest(this);
new TestSQLInjection().runTest(this);
new TestSessionsLocks().runTest(this);
new TestSequence().runTest(this);
new TestSpaceReuse().runTest(this);
new TestSpeed().runTest(this);
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.test.TestBase;
public class TestSessionsLocks extends TestBase {
public void test() throws Exception {
testCancelStatement();
testLocks();
}
private void testLocks() throws Exception {
deleteDb("sessionsLocks");
Connection conn = getConnection("sessionsLocks;MULTI_THREADED=1");
Statement stat = conn.createStatement();
ResultSet rs;
rs = stat.executeQuery("select * from information_schema.locks order by session_id");
checkFalse(rs.next());
Connection conn2 = getConnection("sessionsLocks");
Statement stat2 = conn2.createStatement();
stat2.execute("create table test(id int primary key, name varchar)");
conn2.setAutoCommit(false);
stat2.execute("insert into test values(1, 'Hello')");
rs = stat.executeQuery("select * from information_schema.locks order by session_id");
rs.next();
check("PUBLIC", rs.getString("TABLE_SCHEMA"));
check("TEST", rs.getString("TABLE_NAME"));
rs.getString("SESSION_ID");
if (config.mvcc) {
check("READ", rs.getString("LOCK_TYPE"));
} else {
check("WRITE", rs.getString("LOCK_TYPE"));
}
checkFalse(rs.next());
conn2.commit();
conn2.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
stat2.execute("SELECT * FROM TEST");
rs = stat.executeQuery("select * from information_schema.locks order by session_id");
if (!config.mvcc) {
rs.next();
check("PUBLIC", rs.getString("TABLE_SCHEMA"));
check("TEST", rs.getString("TABLE_NAME"));
rs.getString("SESSION_ID");
check("READ", rs.getString("LOCK_TYPE"));
}
checkFalse(rs.next());
conn2.commit();
rs = stat.executeQuery("select * from information_schema.locks order by session_id");
checkFalse(rs.next());
conn.close();
conn2.close();
}
public void testCancelStatement() throws Exception {
deleteDb("sessionsLocks");
Connection conn = getConnection("sessionsLocks;MULTI_THREADED=1");
Statement stat = conn.createStatement();
ResultSet rs;
rs = stat.executeQuery("select * from information_schema.sessions order by SESSION_START, ID");
rs.next();
int sessionId = rs.getInt("ID");
rs.getString("USER_NAME");
rs.getTimestamp("SESSION_START");
rs.getString("STATEMENT");
rs.getTimestamp("STATEMENT_START");
checkFalse(rs.next());
Connection conn2 = getConnection("sessionsLocks");
final Statement stat2 = conn2.createStatement();
rs = stat.executeQuery("select * from information_schema.sessions order by SESSION_START, ID");
check(rs.next());
check(sessionId, rs.getInt("ID"));
check(rs.next());
int otherId = rs.getInt("ID");
check(otherId != sessionId);
checkFalse(rs.next());
stat2.execute("set throttle 1");
final boolean[] done = new boolean[1];
Runnable runnable = new Runnable() {
public void run() {
try {
stat2.execute("select count(*) from system_range(1, 10000000) t1, system_range(1, 10000000) t2");
new Error("Unexpected success").printStackTrace();
} catch (SQLException e) {
done[0] = true;
}
}
};
new Thread(runnable).start();
while (true) {
Thread.sleep(1000);
rs = stat.executeQuery("CALL CANCEL_SESSION(" + otherId + ")");
rs.next();
if (rs.getBoolean(1)) {
Thread.sleep(100);
check(done[0]);
break;
} else {
System.out.println("no statement is executing yet");
}
}
conn2.close();
conn.close();
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论