提交 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 { ...@@ -64,10 +64,11 @@ public abstract class Command implements CommandInterface {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
Database database = session.getDatabase(); Database database = session.getDatabase();
Object sync = database.getMultiThreaded() ? (Object) session : (Object) database; Object sync = database.getMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled();
synchronized (sync) { synchronized (sync) {
try { try {
database.checkPowerOff(); database.checkPowerOff();
session.setCurrentCommand(this); session.setCurrentCommand(this, startTime);
return query(maxrows); return query(maxrows);
} catch (Throwable e) { } catch (Throwable e) {
SQLException s = Message.convert(e); SQLException s = Message.convert(e);
...@@ -92,7 +93,7 @@ public abstract class Command implements CommandInterface { ...@@ -92,7 +93,7 @@ public abstract class Command implements CommandInterface {
} }
private void stop() throws SQLException { private void stop() throws SQLException {
session.setCurrentCommand(null); session.setCurrentCommand(null, 0);
if (!isTransactional()) { if (!isTransactional()) {
session.commit(true); session.commit(true);
} else if (session.getAutoCommit()) { } else if (session.getAutoCommit()) {
...@@ -115,9 +116,10 @@ public abstract class Command implements CommandInterface { ...@@ -115,9 +116,10 @@ public abstract class Command implements CommandInterface {
startTime = System.currentTimeMillis(); startTime = System.currentTimeMillis();
Database database = session.getDatabase(); Database database = session.getDatabase();
Object sync = database.getMultiThreaded() ? (Object) session : (Object) database; Object sync = database.getMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled();
synchronized (sync) { synchronized (sync) {
int rollback = session.getLogId(); int rollback = session.getLogId();
session.setCurrentCommand(this); session.setCurrentCommand(this, startTime);
try { try {
database.checkPowerOff(); database.checkPowerOff();
return update(); return update();
......
...@@ -3656,6 +3656,12 @@ public class Parser { ...@@ -3656,6 +3656,12 @@ public class Parser {
Set command = new Set(session, SetTypes.MVCC); Set command = new Set(session, SetTypes.MVCC);
command.setInt(value ? 1 : 0); command.setInt(value ? 1 : 0);
return command; 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")) { } else if (readIf("IGNORECASE")) {
readIfEqualOrTo(); readIfEqualOrTo();
boolean value = readBooleanSetting(); boolean value = readBooleanSetting();
......
...@@ -94,20 +94,17 @@ public class SelectUnion extends Query { ...@@ -94,20 +94,17 @@ public class SelectUnion extends Query {
} }
switch (unionType) { switch (unionType) {
case UNION: case UNION:
case EXCEPT:
left.setDistinct(true); left.setDistinct(true);
right.setDistinct(true); right.setDistinct(true);
result.setDistinct(); result.setDistinct();
break; break;
case UNION_ALL: case UNION_ALL:
break; break;
case EXCEPT: case INTERSECT:
result.setDistinct();
// fall through
case INTERSECT: {
left.setDistinct(true); left.setDistinct(true);
right.setDistinct(true); right.setDistinct(true);
break; break;
}
default: default:
throw Message.getInternalError("type=" + unionType); throw Message.getInternalError("type=" + unionType);
} }
......
...@@ -274,6 +274,12 @@ public class Set extends Prepared { ...@@ -274,6 +274,12 @@ public class Set extends Prepared {
database.setMaxOperationMemory(value); database.setMaxOperationMemory(value);
break; break;
} }
case SetTypes.EXCLUSIVE: {
session.getUser().checkAdmin();
int value = getIntValue();
database.setExclusiveSession(value == 1 ? session : null);
break;
}
default: default:
throw Message.getInternalError("type="+type); throw Message.getInternalError("type="+type);
} }
......
...@@ -20,7 +20,7 @@ public class SetTypes { ...@@ -20,7 +20,7 @@ public class SetTypes {
public static final int LOG = 19, THROTTLE = 20, MAX_MEMORY_UNDO = 21, MAX_LENGTH_INPLACE_LOB = 22; 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 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 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(); private static ObjectArray types = new ObjectArray();
...@@ -57,6 +57,7 @@ public class SetTypes { ...@@ -57,6 +57,7 @@ public class SetTypes {
setType(REFERENTIAL_INTEGRITY, "REFERENTIAL_INTEGRITY"); setType(REFERENTIAL_INTEGRITY, "REFERENTIAL_INTEGRITY");
setType(MVCC, "MVCC"); setType(MVCC, "MVCC");
setType(MAX_OPERATION_MEMORY, "MAX_OPERATION_MEMORY"); setType(MAX_OPERATION_MEMORY, "MAX_OPERATION_MEMORY");
setType(EXCLUSIVE, "EXCLUSIVE");
} }
private static void setType(int type, String name) { private static void setType(int type, String name) {
......
...@@ -315,6 +315,7 @@ public class ErrorCode { ...@@ -315,6 +315,7 @@ public class ErrorCode {
public static final int AGGREGATE_NOT_FOUND_1 = 90132; public static final int AGGREGATE_NOT_FOUND_1 = 90132;
public static final int CANNOT_CHANGE_SETTING_WHEN_OPEN_1 = 90133; 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 ACCESS_DENIED_TO_CLASS_1 = 90134;
public static final int DATABASE_IS_IN_EXCLUSIVE_MODE = 90135;
/** /**
* INTERNAL * INTERNAL
......
...@@ -7,9 +7,11 @@ package org.h2.engine; ...@@ -7,9 +7,11 @@ package org.h2.engine;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
...@@ -85,7 +87,8 @@ public class Database implements DataHandler { ...@@ -85,7 +87,8 @@ public class Database implements DataHandler {
private final HashMap userDataTypes = new HashMap(); private final HashMap userDataTypes = new HashMap();
private final HashMap aggregates = new HashMap(); private final HashMap aggregates = new HashMap();
private final HashMap comments = 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 BitField objectIds = new BitField();
private final Object lobSyncObject = new Object(); private final Object lobSyncObject = new Object();
...@@ -772,7 +775,10 @@ public class Database implements DataHandler { ...@@ -772,7 +775,10 @@ public class Database implements DataHandler {
return getUser(name, Message.getSQLException(ErrorCode.USER_NOT_FOUND_1, name)); 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); Session session = new Session(this, user, ++nextSessionId);
sessions.add(session); sessions.add(session);
traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName); traceSystem.getTrace(Trace.SESSION).info("connecting #" + session.getId() + " to " + databaseName);
...@@ -785,6 +791,9 @@ public class Database implements DataHandler { ...@@ -785,6 +791,9 @@ public class Database implements DataHandler {
public synchronized void removeSession(Session session) throws SQLException { public synchronized void removeSession(Session session) throws SQLException {
if (session != null) { if (session != null) {
if (exclusiveSession == session) {
exclusiveSession = null;
}
sessions.remove(session); sessions.remove(session);
if (session != systemSession) { if (session != systemSession) {
traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId()); traceSystem.getTrace(Trace.SESSION).info("disconnecting #" + session.getId());
...@@ -1032,7 +1041,7 @@ public class Database implements DataHandler { ...@@ -1032,7 +1041,7 @@ public class Database implements DataHandler {
return log; return log;
} }
public synchronized Session[] getSessions() { public Session[] getSessions() {
Session[] list = new Session[sessions.size()]; Session[] list = new Session[sessions.size()];
sessions.toArray(list); sessions.toArray(list);
return list; return list;
...@@ -1624,4 +1633,12 @@ public class Database implements DataHandler { ...@@ -1624,4 +1633,12 @@ public class Database implements DataHandler {
return maxOperationMemory; return maxOperationMemory;
} }
public Session getExclusiveSession() {
return exclusiveSession;
}
public void setExclusiveSession(Session session) {
this.exclusiveSession = session;
}
} }
...@@ -73,7 +73,8 @@ public class Session implements SessionInterface { ...@@ -73,7 +73,8 @@ public class Session implements SessionInterface {
private String currentTransactionName; private String currentTransactionName;
private boolean isClosed; private boolean isClosed;
private boolean rollbackMode; private boolean rollbackMode;
private long loginTime = System.currentTimeMillis(); private long sessionStart = System.currentTimeMillis();
private long currentCommandStart;
public Session() { public Session() {
} }
...@@ -498,8 +499,9 @@ public class Session implements SessionInterface { ...@@ -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.currentCommand = command;
this.currentCommandStart = startTime;
} }
public void checkCancelled() throws SQLException { public void checkCancelled() throws SQLException {
...@@ -508,9 +510,12 @@ public class Session implements SessionInterface { ...@@ -508,9 +510,12 @@ public class Session implements SessionInterface {
} }
} }
public String getCurrentCommand() { public Command getCurrentCommand() {
Command c = currentCommand; return currentCommand;
return c == null ? null : c.toString(); }
public long getCurrentCommandStart() {
return currentCommandStart;
} }
public boolean getAllowLiterals() { public boolean getAllowLiterals() {
...@@ -609,8 +614,8 @@ public class Session implements SessionInterface { ...@@ -609,8 +614,8 @@ public class Session implements SessionInterface {
return rollbackMode; return rollbackMode;
} }
public long getLoginTime() { public long getSessionStart() {
return loginTime; return sessionStart;
} }
public Table[] getLocks() { public Table[] getLocks() {
...@@ -621,4 +626,18 @@ public class Session implements SessionInterface { ...@@ -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 { ...@@ -57,8 +57,6 @@ public class BtreeIndex extends BaseIndex implements RecordReader {
head = (BtreeHead) rec; head = (BtreeHead) rec;
} }
if (head != null && head.getConsistent()) { if (head != null && head.getConsistent()) {
int testing;
// setRoot((BtreePage) storage.getRecord(session, head.getRootPosition()));
needRebuild = false; needRebuild = false;
rowCount = table.getRowCount(session); rowCount = table.getRowCount(session);
} else { } else {
......
...@@ -155,6 +155,7 @@ ...@@ -155,6 +155,7 @@
90132=Aggregate {0} not found 90132=Aggregate {0} not found
90133=Cannot change the setting {0} when the database is already open 90133=Cannot change the setting {0} when the database is already open
90134=Access to the class {0} is denied 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} HY000=General error\: {0}
HY004=Unknown data type\: {0} HY004=Unknown data type\: {0}
HYC00=Feature not supported HYC00=Feature not supported
......
...@@ -856,6 +856,19 @@ Admin rights are required to execute this command. ...@@ -856,6 +856,19 @@ Admin rights are required to execute this command.
SET DEFAULT_TABLE_TYPE MEMORY 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"," "Commands (Other)","SET IGNORECASE","
SET IGNORECASE {TRUE|FALSE} SET IGNORECASE {TRUE|FALSE}
"," ","
...@@ -2559,6 +2572,18 @@ Returns true if auto commit is switched on for this session. ...@@ -2559,6 +2572,18 @@ Returns true if auto commit is switched on for this session.
AUTOCOMMIT() 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"," "Functions (System)","CASEWHEN Function","
CASEWHEN(boolean, aValue, bValue): value CASEWHEN(boolean, aValue, bValue): value
"," ","
......
...@@ -333,6 +333,7 @@ public class FtpControl extends Thread { ...@@ -333,6 +333,7 @@ public class FtpControl extends Thread {
} else if ("XRMD".equals(command)) { } else if ("XRMD".equals(command)) {
processRemoveDir(param); processRemoveDir(param);
} }
break;
default: default:
break; break;
} }
......
...@@ -114,6 +114,7 @@ public class WebServer implements Service { ...@@ -114,6 +114,7 @@ public class WebServer implements Service {
private ShutdownHandler shutdownHandler; private ShutdownHandler shutdownHandler;
private Thread listenerThread; private Thread listenerThread;
private boolean ifExists; private boolean ifExists;
private boolean allowScript;
byte[] getFile(String file) throws IOException { byte[] getFile(String file) throws IOException {
trace("getFile <" + file + ">"); trace("getFile <" + file + ">");
...@@ -196,6 +197,8 @@ public class WebServer implements Service { ...@@ -196,6 +197,8 @@ public class WebServer implements Service {
ssl = Boolean.valueOf(args[++i]).booleanValue(); ssl = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-webAllowOthers".equals(a)) { } else if ("-webAllowOthers".equals(a)) {
allowOthers = Boolean.valueOf(args[++i]).booleanValue(); allowOthers = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-webScript".equals(a)) {
allowScript = Boolean.valueOf(args[++i]).booleanValue();
} else if ("-baseDir".equals(a)) { } else if ("-baseDir".equals(a)) {
String baseDir = args[++i]; String baseDir = args[++i];
SysProperties.setBaseDir(baseDir); SysProperties.setBaseDir(baseDir);
...@@ -508,4 +511,8 @@ public class WebServer implements Service { ...@@ -508,4 +511,8 @@ public class WebServer implements Service {
this.shutdownHandler = shutdownHandler; this.shutdownHandler = shutdownHandler;
} }
public boolean getAllowScript() {
return allowScript;
}
} }
...@@ -5,13 +5,20 @@ ...@@ -5,13 +5,20 @@
package org.h2.server.web; package org.h2.server.web;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.Socket; import java.net.Socket;
import java.security.SecureClassLoader;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
...@@ -40,12 +47,12 @@ import org.h2.engine.Constants; ...@@ -40,12 +47,12 @@ import org.h2.engine.Constants;
import org.h2.jdbc.JdbcSQLException; import org.h2.jdbc.JdbcSQLException;
import org.h2.message.TraceSystem; import org.h2.message.TraceSystem;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
import org.h2.util.ObjectUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
import org.h2.util.NetUtils; import org.h2.util.NetUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.util.ScriptReader; import org.h2.util.ScriptReader;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -1018,7 +1025,17 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1018,7 +1025,17 @@ class WebThread extends Thread implements DatabaseEventListener {
try { try {
Connection conn = session.getConnection(); Connection conn = session.getConnection();
String result; 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); conn.setAutoCommit(true);
result = "${text.result.autoCommitOn}"; result = "${text.result.autoCommitOn}";
} else if ("@AUTOCOMMIT FALSE".equals(sql)) { } else if ("@AUTOCOMMIT FALSE".equals(sql)) {
...@@ -1068,6 +1085,94 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1068,6 +1085,94 @@ class WebThread extends Thread implements DatabaseEventListener {
return "result.jsp"; 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() { private String editResult() {
ResultSet rs = session.result; ResultSet rs = session.result;
int row = Integer.parseInt(attributes.getProperty("row")); int row = Integer.parseInt(attributes.getProperty("row"));
...@@ -1083,7 +1188,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1083,7 +1188,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) { for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
String x = attributes.getProperty("r" + row + "c" + (i + 1)); String x = attributes.getProperty("r" + row + "c" + (i + 1));
rs.updateString(i + 1, x); rs.updateString(i + 1, unescapeData(x));
} }
if (insert) { if (insert) {
rs.insertRow(); rs.insertRow();
...@@ -1611,7 +1716,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1611,7 +1716,7 @@ class WebThread extends Thread implements DatabaseEventListener {
buff.append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))); buff.append(PageParser.escapeHtml(meta.getColumnLabel(i + 1)));
buff.append("</td>"); buff.append("</td>");
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>"); buff.append("</td></tr>");
} }
} }
...@@ -1645,7 +1750,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1645,7 +1750,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
for (int i = 0; i < columns; i++) { for (int i = 0; i < columns; i++) {
buff.append("<td>"); buff.append("<td>");
buff.append(PageParser.escapeHtml(rs.getString(i + 1))); buff.append(escapeData(rs.getString(i + 1)));
buff.append("</td>"); buff.append("</td>");
} }
buff.append("</tr>"); buff.append("</tr>");
...@@ -1713,6 +1818,26 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1713,6 +1818,26 @@ class WebThread extends Thread implements DatabaseEventListener {
return "index.do"; 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() { private String settingRemove() {
String setting = attributes.getProperty("name", ""); String setting = attributes.getProperty("name", "");
server.removeSetting(setting); server.removeSetting(setting);
......
...@@ -45,8 +45,8 @@ function editRow(row, session, write, undo) { ...@@ -45,8 +45,8 @@ function editRow(row, session, write, undo) {
for(i=1; i<table.rows.length; i++) { for(i=1; i<table.rows.length; i++) {
var cell = table.rows[i].cells[0]; var cell = table.rows[i].cells[0];
if(i == y) { 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 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="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 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; cell.innerHTML = edit + undo;
} else { } else {
cell.innerHTML = ''; cell.innerHTML = '';
...@@ -56,7 +56,36 @@ function editRow(row, session, write, undo) { ...@@ -56,7 +56,36 @@ function editRow(row, session, write, undo) {
for(i=1; i<cells.length; i++) { for(i=1; i<cells.length; i++) {
var cell = cells[i]; var cell = cells[i];
var text = getInnerText(cell); 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;
} }
} }
......
...@@ -16,6 +16,7 @@ import java.sql.Timestamp; ...@@ -16,6 +16,7 @@ import java.sql.Timestamp;
import java.text.Collator; import java.text.Collator;
import java.util.Locale; import java.util.Locale;
import org.h2.command.Command;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintCheck; import org.h2.constraint.ConstraintCheck;
...@@ -434,8 +435,9 @@ public class MetaTable extends Table { ...@@ -434,8 +435,9 @@ public class MetaTable extends Table {
cols = createColumns(new String[]{ cols = createColumns(new String[]{
"ID INT", "ID INT",
"USER_NAME", "USER_NAME",
"CURRENT_STATEMENT", "SESSION_START",
"LOGIN_TIME", "STATEMENT",
"STATEMENT_START"
}); });
break; break;
} }
...@@ -707,6 +709,7 @@ public class MetaTable extends Table { ...@@ -707,6 +709,7 @@ public class MetaTable extends Table {
} }
} }
add(rows, new String[] { "MVCC", database.isMultiVersion() ? "TRUE" : "FALSE" }); 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[] { "MODE", database.getMode().getName() });
add(rows, new String[] { "MULTI_THREADED", database.getMultiThreaded() ? "1" : "0"}); add(rows, new String[] { "MULTI_THREADED", database.getMultiThreaded() ? "1" : "0"});
DiskFile dataFile = database.getDataFile(); DiskFile dataFile = database.getDataFile();
...@@ -1205,11 +1208,13 @@ public class MetaTable extends Table { ...@@ -1205,11 +1208,13 @@ public class MetaTable extends Table {
for (int i = 0; i < sessions.length; i++) { for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i]; Session s = sessions[i];
if (admin || s == session) { if (admin || s == session) {
Command command = s.getCurrentCommand();
add(rows, new String[] { add(rows, new String[] {
"" + s.getId(), // ID "" + s.getId(), // ID
s.getUser().getName(), // USER_NAME s.getUser().getName(), // USER_NAME
s.getCurrentCommand(), // CURRENT_COMMAND new Timestamp(s.getSessionStart()).toString(), // SESSION_START
new Timestamp(s.getLoginTime()).toString(), // LOGIN_TIME command == null ? null : command.toString(), // STATEMENT
new Timestamp(s.getCurrentCommandStart()).toString() // STATEMENT_START
}); });
} }
} }
......
...@@ -150,6 +150,8 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -150,6 +150,8 @@ public class Server implements Runnable, ShutdownHandler {
i++; i++;
} else if ("-webPort".equals(a)) { } else if ("-webPort".equals(a)) {
i++; i++;
} else if ("-webScript".equals(a)) {
i++;
} else if ("-webSSL".equals(a)) { } else if ("-webSSL".equals(a)) {
i++; i++;
} else { } else {
......
...@@ -40,6 +40,7 @@ import org.h2.test.db.TestSQLInjection; ...@@ -40,6 +40,7 @@ import org.h2.test.db.TestSQLInjection;
import org.h2.test.db.TestScript; import org.h2.test.db.TestScript;
import org.h2.test.db.TestScriptSimple; import org.h2.test.db.TestScriptSimple;
import org.h2.test.db.TestSequence; import org.h2.test.db.TestSequence;
import org.h2.test.db.TestSessionsLocks;
import org.h2.test.db.TestSpaceReuse; import org.h2.test.db.TestSpaceReuse;
import org.h2.test.db.TestSpeed; import org.h2.test.db.TestSpeed;
import org.h2.test.db.TestTempTables; import org.h2.test.db.TestTempTables;
...@@ -151,8 +152,15 @@ java org.h2.test.TestAll timer ...@@ -151,8 +152,15 @@ java org.h2.test.TestAll timer
/* /*
write simple test for test & document exclusive mode
NFORMATION_SCHEMA.SESSIONS and LOCKS 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 C:\temp\test\db
...@@ -576,6 +584,7 @@ Features of H2 ...@@ -576,6 +584,7 @@ Features of H2
new TestRights().runTest(this); new TestRights().runTest(this);
new TestRunscript().runTest(this); new TestRunscript().runTest(this);
new TestSQLInjection().runTest(this); new TestSQLInjection().runTest(this);
new TestSessionsLocks().runTest(this);
new TestSequence().runTest(this); new TestSequence().runTest(this);
new TestSpaceReuse().runTest(this); new TestSpaceReuse().runTest(this);
new TestSpeed().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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论