提交 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,10 +20,10 @@ public class SetTypes { ...@@ -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 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();
static { static {
setType(IGNORECASE, "IGNORECASE"); setType(IGNORECASE, "IGNORECASE");
setType(MAX_LOG_SIZE, "MAX_LOG_SIZE"); setType(MAX_LOG_SIZE, "MAX_LOG_SIZE");
...@@ -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);
......
/* /*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html). * Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
*/ */
addEvent(window, "load", initSort); addEvent(window, "load", initSort);
function addEvent(elm, evType, fn, useCapture) { function addEvent(elm, evType, fn, useCapture) {
...@@ -26,7 +26,7 @@ function initSort() { ...@@ -26,7 +26,7 @@ function initSort() {
} }
var tables = document.getElementsByTagName("table"); var tables = document.getElementsByTagName("table");
for (var i=0; i<tables.length; i++) { for (var i=0; i<tables.length; i++) {
table = tables[i]; table = tables[i];
if (table.rows && table.rows.length > 0) { if (table.rows && table.rows.length > 0) {
var header = table.rows[0]; var header = table.rows[0];
for(var j=0;j<header.cells.length;j++) { for(var j=0;j<header.cells.length;j++) {
...@@ -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,10 +56,39 @@ function editRow(row, session, write, undo) { ...@@ -56,10 +56,39 @@ 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;
}
}
function getInnerText(el) { function getInnerText(el) {
if (typeof el == "string") return el; if (typeof el == "string") return el;
if (typeof el == "undefined") { return el }; if (typeof el == "undefined") { return el };
......
...@@ -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
}); });
} }
} }
......
...@@ -28,12 +28,12 @@ import org.h2.util.StartBrowser; ...@@ -28,12 +28,12 @@ import org.h2.util.StartBrowser;
* This tool can be used to start various database servers (listeners). * This tool can be used to start various database servers (listeners).
*/ */
public class Server implements Runnable, ShutdownHandler { public class Server implements Runnable, ShutdownHandler {
private Service service; private Service service;
private static final int EXIT_ERROR = 1; private static final int EXIT_ERROR = 1;
private Server web, tcp, pg, ftp; private Server web, tcp, pg, ftp;
private ShutdownHandler shutdownHandler; private ShutdownHandler shutdownHandler;
private void showUsage(String a, PrintStream out) { private void showUsage(String a, PrintStream out) {
if (a != null) { if (a != null) {
out.println("Unknown option: " + a); out.println("Unknown option: " + a);
...@@ -53,30 +53,30 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -53,30 +53,30 @@ public class Server implements Runnable, ShutdownHandler {
out.println("-tcp (start the TCP Server)"); out.println("-tcp (start the TCP Server)");
out.println("-tcpAllowOthers {true|false}"); out.println("-tcpAllowOthers {true|false}");
out.println("-tcpPort <port> (default: " + TcpServer.DEFAULT_PORT+")"); 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("-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("-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("-tcpShutdownForce {true|false} (don't wait for other connections to close)");
out.println(); out.println();
out.println("-pg (start the PG Server)"); 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("-pgPort <port> (default: " + PgServer.DEFAULT_PORT+")");
out.println(); out.println();
out.println("-ftp (start the FTP Server)"); out.println("-ftp (start the FTP Server)");
out.println("-ftpPort <port> (default: " + Constants.DEFAULT_FTP_PORT+")"); 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("-ftpRead <readUserName> (default: " + FtpServer.DEFAULT_READ+")");
out.println("-ftpWrite <writeUserName> (default: " + FtpServer.DEFAULT_WRITE+")"); 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();
out.println("-log {true|false} (enable or disable logging, for all servers)"); 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("-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)"); out.println("-ifExists {true|false} (only existing databases may be opened, for all servers)");
} }
public Server() { public Server() {
} }
/** /**
* The command line interface for this tool. * The command line interface for this tool.
* The options must be split into strings like this: "-baseDir", "/temp/data",... * The options must be split into strings like this: "-baseDir", "/temp/data",...
...@@ -114,7 +114,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -114,7 +114,7 @@ public class Server implements Runnable, ShutdownHandler {
* </li><li>-ftpWrite {writeUserName} * </li><li>-ftpWrite {writeUserName}
* </li><li>-ftpWritePassword {password} * </li><li>-ftpWritePassword {password}
* </li></ul> * </li></ul>
* *
* @param args the command line arguments * @param args the command line arguments
* @throws SQLException * @throws SQLException
*/ */
...@@ -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 {
...@@ -267,10 +269,10 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -267,10 +269,10 @@ public class Server implements Runnable, ShutdownHandler {
// ignore (status is displayed) // ignore (status is displayed)
e.printStackTrace(); e.printStackTrace();
exitCode = EXIT_ERROR; exitCode = EXIT_ERROR;
} }
out.println(web.getStatus()); out.println(web.getStatus());
// start browser anyway (even if the server is already running) // start browser anyway (even if the server is already running)
// because some people don't look at the output, // because some people don't look at the output,
// but are wondering why nothing happens // but are wondering why nothing happens
if (browserStart) { if (browserStart) {
StartBrowser.openURL(web.getURL()); StartBrowser.openURL(web.getURL());
...@@ -289,22 +291,22 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -289,22 +291,22 @@ public class Server implements Runnable, ShutdownHandler {
} }
return exitCode; return exitCode;
} }
/** /**
* Shutdown a TCP server. If force is set to false, the server will not allow new connections, * 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. * 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 * After calling the method with force=false, it is not possible to call it again with
* force=true because new connections are not allowed. * force=true because new connections are not allowed.
* Example: * Example:
* <pre>Server.shutdownTcpServer("tcp://localhost:9094", password, true);</pre> * <pre>Server.shutdownTcpServer("tcp://localhost:9094", password, true);</pre>
* *
* @param url example: tcp://localhost:9094 * @param url example: tcp://localhost:9094
* @param password the password to use ("" for no password) * @param password the password to use ("" for no password)
* @param force the shutdown (don't wait) * @param force the shutdown (don't wait)
* @throws ClassNotFoundException * @throws ClassNotFoundException
* @throws SQLException * @throws SQLException
*/ */
public static void shutdownTcpServer(String url, String password, boolean force) throws SQLException { public static void shutdownTcpServer(String url, String password, boolean force) throws SQLException {
int port = Constants.DEFAULT_SERVER_PORT; int port = Constants.DEFAULT_SERVER_PORT;
int idx = url.indexOf(':', "jdbc:h2:".length()); int idx = url.indexOf(':', "jdbc:h2:".length());
...@@ -376,7 +378,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -376,7 +378,7 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new web server, but does not start it yet. * Create a new web server, but does not start it yet.
* Example: * Example:
* <pre>Server server = Server.createWebServer(new String[]{"-log", "true"}).start();</pre> * <pre>Server server = Server.createWebServer(new String[]{"-log", "true"}).start();</pre>
* *
* @param args * @param args
* @return the server * @return the server
*/ */
...@@ -391,7 +393,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -391,7 +393,7 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new ftp server, but does not start it yet. * Create a new ftp server, but does not start it yet.
* Example: * Example:
* <pre>Server server = Server.createFtpServer(new String[]{"-log", "true"}).start();</pre> * <pre>Server server = Server.createFtpServer(new String[]{"-log", "true"}).start();</pre>
* *
* @param args * @param args
* @return the server * @return the server
*/ */
...@@ -403,26 +405,26 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -403,26 +405,26 @@ public class Server implements Runnable, ShutdownHandler {
* Create a new TCP server, but does not start it yet. * Create a new TCP server, but does not start it yet.
* Example: * Example:
* <pre>Server server = Server.createTcpServer(new String[]{"-tcpAllowOthers", "true"}).start();</pre> * <pre>Server server = Server.createTcpServer(new String[]{"-tcpAllowOthers", "true"}).start();</pre>
* *
* @param args * @param args
* @return the server * @return the server
*/ */
public static Server createTcpServer(String[] args) throws SQLException { public static Server createTcpServer(String[] args) throws SQLException {
return new Server(new TcpServer(), args); return new Server(new TcpServer(), args);
} }
/** /**
* Create a new PG server, but does not start it yet. * Create a new PG server, but does not start it yet.
* Example: * Example:
* <pre>Server server = Server.createPgServer(new String[]{"-pgAllowOthers", "true"}).start();</pre> * <pre>Server server = Server.createPgServer(new String[]{"-pgAllowOthers", "true"}).start();</pre>
* *
* @param args * @param args
* @return the server * @return the server
*/ */
public static Server createPgServer(String[] args) throws SQLException { public static Server createPgServer(String[] args) throws SQLException {
return new Server(new PgServer(), args); return new Server(new PgServer(), args);
} }
/** /**
* Tries to start the server. * Tries to start the server.
* @return the server if successful * @return the server if successful
...@@ -473,7 +475,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -473,7 +475,7 @@ public class Server implements Runnable, ShutdownHandler {
/** /**
* Checks if the server is running. * Checks if the server is running.
* *
* @return if the server is running * @return if the server is running
*/ */
public boolean isRunning() { public boolean isRunning() {
...@@ -486,7 +488,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -486,7 +488,7 @@ public class Server implements Runnable, ShutdownHandler {
public void stop() { public void stop() {
service.stop(); service.stop();
} }
/** /**
* Gets the URL of this server. * Gets the URL of this server.
* @return the url * @return the url
...@@ -514,7 +516,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -514,7 +516,7 @@ public class Server implements Runnable, ShutdownHandler {
TraceSystem.traceThrowable(e); TraceSystem.traceThrowable(e);
} }
} }
/** /**
* INTERNAL * INTERNAL
*/ */
...@@ -524,7 +526,7 @@ public class Server implements Runnable, ShutdownHandler { ...@@ -524,7 +526,7 @@ public class Server implements Runnable, ShutdownHandler {
/** /**
* INTERNAL * INTERNAL
*/ */
public void shutdown() { public void shutdown() {
if (shutdownHandler != null) { if (shutdownHandler != null) {
shutdownHandler.shutdown(); shutdownHandler.shutdown();
......
...@@ -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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论