提交 488ecc5e authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 e9b4498c
...@@ -509,6 +509,8 @@ public class Database implements DataHandler { ...@@ -509,6 +509,8 @@ public class Database implements DataHandler {
addMetaData(MetaTable.CONSTANTS); addMetaData(MetaTable.CONSTANTS);
addMetaData(MetaTable.DOMAINS); addMetaData(MetaTable.DOMAINS);
addMetaData(MetaTable.TRIGGERS); addMetaData(MetaTable.TRIGGERS);
addMetaData(MetaTable.SESSIONS);
addMetaData(MetaTable.LOCKS);
starting = true; starting = true;
Cursor cursor = metaIdIndex.find(systemSession, null, null); Cursor cursor = metaIdIndex.find(systemSession, null, null);
// first, create all function aliases and sequences because // first, create all function aliases and sequences because
......
...@@ -30,8 +30,8 @@ import org.h2.result.Row; ...@@ -30,8 +30,8 @@ import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ObjectUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
...@@ -73,6 +73,7 @@ public class Session implements SessionInterface { ...@@ -73,6 +73,7 @@ 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();
public Session() { public Session() {
} }
...@@ -507,6 +508,11 @@ public class Session implements SessionInterface { ...@@ -507,6 +508,11 @@ public class Session implements SessionInterface {
} }
} }
public String getCurrentCommand() {
Command c = currentCommand;
return c == null ? null : c.toString();
}
public boolean getAllowLiterals() { public boolean getAllowLiterals() {
return allowLiterals; return allowLiterals;
} }
...@@ -603,4 +609,16 @@ public class Session implements SessionInterface { ...@@ -603,4 +609,16 @@ public class Session implements SessionInterface {
return rollbackMode; return rollbackMode;
} }
public long getLoginTime() {
return loginTime;
}
public Table[] getLocks() {
synchronized (database) {
Table[] list = new Table[locks.size()];
locks.toArray(list);
return list;
}
}
} }
...@@ -72,7 +72,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -72,7 +72,7 @@ public class Function extends Expression implements FunctionCall {
OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66, REPLACE = 67, RIGHT = 68, RTRIM = 69, SOUNDEX = 70, OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66, REPLACE = 67, RIGHT = 68, RTRIM = 69, SOUNDEX = 70,
SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78, SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78,
STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84, STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84,
XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89; XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91;
public static final int CURDATE = 100, CURTIME = 101, DATEADD = 102, DATEDIFF = 103, DAYNAME = 104, public static final int CURDATE = 100, CURTIME = 101, DATEADD = 102, DATEDIFF = 103, DAYNAME = 104,
DAYOFMONTH = 105, DAYOFWEEK = 106, DAYOFYEAR = 107, HOUR = 108, MINUTE = 109, MONTH = 110, MONTHNAME = 111, DAYOFMONTH = 105, DAYOFWEEK = 106, DAYOFYEAR = 107, HOUR = 108, MINUTE = 109, MONTH = 110, MONTHNAME = 111,
...@@ -159,13 +159,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -159,13 +159,9 @@ public class Function extends Expression implements FunctionCall {
addFunction("PI", PI, 0, Value.DOUBLE); addFunction("PI", PI, 0, Value.DOUBLE);
addFunction("POWER", POWER, 2, Value.DOUBLE); addFunction("POWER", POWER, 2, Value.DOUBLE);
addFunction("RADIANS", RADIANS, 1, Value.DOUBLE); addFunction("RADIANS", RADIANS, 1, Value.DOUBLE);
addFunctionNotConst("RAND", RAND, VAR_ARGS, Value.DOUBLE); // no args: // RAND without argument: get the next value
// regular // RAND with one argument: seed the random generator
// rand; addFunctionNotConst("RAND", RAND, VAR_ARGS, Value.DOUBLE);
// with one
// arg: seed
// random
// generator
addFunction("ROUND", ROUND, 2, Value.DOUBLE); addFunction("ROUND", ROUND, 2, Value.DOUBLE);
addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE); addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE);
addFunction("SIGN", SIGN, 1, Value.INT); addFunction("SIGN", SIGN, 1, Value.INT);
...@@ -228,6 +224,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -228,6 +224,8 @@ public class Function extends Expression implements FunctionCall {
addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING); addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING);
addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING); addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING);
addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING); addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING);
addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
// date // date
addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE); addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE);
...@@ -682,6 +680,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -682,6 +680,10 @@ public class Function extends Expression implements FunctionCall {
return ValueString.get(StringUtils.xmlText(v0.getString())); return ValueString.get(StringUtils.xmlText(v0.getString()));
case REGEXP_REPLACE: case REGEXP_REPLACE:
return ValueString.get(v0.getString().replaceAll(v1.getString(), v2.getString())); return ValueString.get(v0.getString().replaceAll(v1.getString(), v2.getString()));
case RPAD:
return ValueString.get(StringUtils.pad(v0.getString(), v1.getInt(), v2 == null ? null : v2.getString(), true));
case LPAD:
return ValueString.get(StringUtils.pad(v0.getString(), v1.getInt(), v2 == null ? null : v2.getString(), false));
// date // date
case DATEADD: case DATEADD:
return ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy())); return ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy()));
...@@ -1290,6 +1292,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1290,6 +1292,8 @@ public class Function extends Expression implements FunctionCall {
case INSTR: case INSTR:
case SUBSTR: case SUBSTR:
case SUBSTRING: case SUBSTRING:
case LPAD:
case RPAD:
min = 2; min = 2;
max = 3; max = 3;
break; break;
......
...@@ -2080,6 +2080,7 @@ Each character needs 16 bits. ...@@ -2080,6 +2080,7 @@ Each character needs 16 bits.
"," ","
BIT_LENGTH(NAME) BIT_LENGTH(NAME)
" "
"Functions (String)","LENGTH"," "Functions (String)","LENGTH","
{LENGTH | CHAR_LENGTH | CHARACTER_LENGTH}(string): int {LENGTH | CHAR_LENGTH | CHARACTER_LENGTH}(string): int
"," ","
...@@ -2088,6 +2089,7 @@ For BLOB, CLOB, BYTES and JAVA_OBJECT, the precision is used. ...@@ -2088,6 +2089,7 @@ For BLOB, CLOB, BYTES and JAVA_OBJECT, the precision is used.
"," ","
LENGTH(NAME) LENGTH(NAME)
" "
"Functions (String)","OCTET_LENGTH"," "Functions (String)","OCTET_LENGTH","
OCTET_LENGTH(string): int OCTET_LENGTH(string): int
"," ","
...@@ -2097,6 +2099,7 @@ Each character needs 2 bytes. ...@@ -2097,6 +2099,7 @@ Each character needs 2 bytes.
"," ","
OCTET_LENGTH(NAME) OCTET_LENGTH(NAME)
" "
"Functions (String)","CHAR"," "Functions (String)","CHAR","
{CHAR | CHR}(int): string {CHAR | CHR}(int): string
"," ","
...@@ -2104,6 +2107,7 @@ Returns the character that represents the ASCII value. ...@@ -2104,6 +2107,7 @@ Returns the character that represents the ASCII value.
"," ","
CHAR(65) CHAR(65)
" "
"Functions (String)","CONCAT"," "Functions (String)","CONCAT","
CONCAT(string, string [,...]): string CONCAT(string, string [,...]): string
"," ","
...@@ -2111,6 +2115,7 @@ Combines strings. ...@@ -2111,6 +2115,7 @@ Combines strings.
"," ","
CONCAT(NAME, '!') CONCAT(NAME, '!')
" "
"Functions (String)","DIFFERENCE"," "Functions (String)","DIFFERENCE","
DIFFERENCE(string, string): int DIFFERENCE(string, string): int
"," ","
...@@ -2118,6 +2123,7 @@ Returns the difference between the sounds of two strings. ...@@ -2118,6 +2123,7 @@ Returns the difference between the sounds of two strings.
"," ","
DIFFERENCE(T1.NAME, T2.NAME) DIFFERENCE(T1.NAME, T2.NAME)
" "
"Functions (String)","HEXTORAW"," "Functions (String)","HEXTORAW","
HEXTORAW(string): string HEXTORAW(string): string
"," ","
...@@ -2126,6 +2132,7 @@ Converts a hex representation of a string to a string. ...@@ -2126,6 +2132,7 @@ Converts a hex representation of a string to a string.
"," ","
HEXTORAW(DATA) HEXTORAW(DATA)
" "
"Functions (String)","RAWTOHEX"," "Functions (String)","RAWTOHEX","
RAWTOHEX(string): string RAWTOHEX(string): string
"," ","
...@@ -2134,6 +2141,7 @@ Converts a string to the hex representation. ...@@ -2134,6 +2141,7 @@ Converts a string to the hex representation.
"," ","
RAWTOHEX(DATA) RAWTOHEX(DATA)
" "
"Functions (String)","INSTR"," "Functions (String)","INSTR","
INSTR(string, searchString, [, startInt]): int INSTR(string, searchString, [, startInt]): int
"," ","
...@@ -2153,6 +2161,7 @@ in the original string. ...@@ -2153,6 +2161,7 @@ in the original string.
"," ","
INSERT(NAME, 1, 1, ' ') INSERT(NAME, 1, 1, ' ')
" "
"Functions (String)","LOWER"," "Functions (String)","LOWER","
{LOWER | LCASE}(string): string {LOWER | LCASE}(string): string
"," ","
...@@ -2160,6 +2169,7 @@ Converts a string to lowercase. ...@@ -2160,6 +2169,7 @@ Converts a string to lowercase.
"," ","
LOWER(NAME) LOWER(NAME)
" "
"Functions (String)","UPPER"," "Functions (String)","UPPER","
{UPPER | UCASE}(string): string {UPPER | UCASE}(string): string
"," ","
...@@ -2167,6 +2177,7 @@ Converts a string to uppercase. ...@@ -2167,6 +2177,7 @@ Converts a string to uppercase.
"," ","
UPPER(NAME) UPPER(NAME)
" "
"Functions (String)","LEFT"," "Functions (String)","LEFT","
LEFT(string, int): string LEFT(string, int): string
"," ","
...@@ -2174,6 +2185,7 @@ Returns the leftmost number of characters. ...@@ -2174,6 +2185,7 @@ Returns the leftmost number of characters.
"," ","
LEFT(NAME, 3) LEFT(NAME, 3)
" "
"Functions (String)","RIGHT"," "Functions (String)","RIGHT","
RIGHT(string, int): string RIGHT(string, int): string
"," ","
...@@ -2181,6 +2193,7 @@ Returns the rightmost number of characters. ...@@ -2181,6 +2193,7 @@ Returns the rightmost number of characters.
"," ","
RIGHT(NAME, 3) RIGHT(NAME, 3)
" "
"Functions (String)","LOCATE"," "Functions (String)","LOCATE","
LOCATE(searchString, string [, startInt]): int LOCATE(searchString, string [, startInt]): int
"," ","
...@@ -2191,6 +2204,7 @@ If position is negative, the rightmost location is returned. ...@@ -2191,6 +2204,7 @@ If position is negative, the rightmost location is returned.
"," ","
LOCATE('.', NAME) LOCATE('.', NAME)
" "
"Functions (String)","POSITION"," "Functions (String)","POSITION","
POSITION(searchString, string): int POSITION(searchString, string): int
"," ","
...@@ -2199,6 +2213,27 @@ See also LOCATE. ...@@ -2199,6 +2213,27 @@ See also LOCATE.
"," ","
POSITION('.', NAME) POSITION('.', NAME)
" "
"Functions (String)","LPAD","
LPAD(string, int[, paddingString]): string
","
Left pad the string to the specified length.
If the length is shorter than the string, it will be truncated at the end.
If the padding string is not set, spaces will be used.
","
LPAD(AMOUNT, 10, '*')
"
"Functions (String)","RPAD","
RPAD(string, int[, paddingString]): string
","
Right pad the string to the specified length.
If the length is shorter than the string, it will be truncated.
If the padding string is not set, spaces will be used.
","
RPAD(TEXT, 10, '-')
"
"Functions (String)","LTRIM"," "Functions (String)","LTRIM","
LTRIM(string): string LTRIM(string): string
"," ","
...@@ -2206,6 +2241,7 @@ Removes all leading spaces from a string. ...@@ -2206,6 +2241,7 @@ Removes all leading spaces from a string.
"," ","
LTRIM(NAME) LTRIM(NAME)
" "
"Functions (String)","RTRIM"," "Functions (String)","RTRIM","
RTRIM(string): string RTRIM(string): string
"," ","
...@@ -2213,6 +2249,7 @@ Removes all trailing spaces from a string. ...@@ -2213,6 +2249,7 @@ Removes all trailing spaces from a string.
"," ","
RTRIM(NAME) RTRIM(NAME)
" "
"Functions (String)","TRIM"," "Functions (String)","TRIM","
TRIM([{LEADING | TRAILING | BOTH} [string] FROM] TRIM([{LEADING | TRAILING | BOTH} [string] FROM]
string): string string): string
...@@ -2775,9 +2812,11 @@ INFORMATION_SCHEMA.FUNCTION_COLUMNS contains the function columns. ...@@ -2775,9 +2812,11 @@ INFORMATION_SCHEMA.FUNCTION_COLUMNS contains the function columns.
INFORMATION_SCHEMA.HELP contains the reference help. INFORMATION_SCHEMA.HELP contains the reference help.
INFORMATION_SCHEMA.INDEXES contains the indexes. INFORMATION_SCHEMA.INDEXES contains the indexes.
INFORMATION_SCHEMA.IN_DOUBT contains all in-doubt transactions. INFORMATION_SCHEMA.IN_DOUBT contains all in-doubt transactions.
INFORMATION_SCHEMA.LOCKS contains all locks.
INFORMATION_SCHEMA.RIGHTS contains the rights. INFORMATION_SCHEMA.RIGHTS contains the rights.
INFORMATION_SCHEMA.ROLES contains the roles. INFORMATION_SCHEMA.ROLES contains the roles.
INFORMATION_SCHEMA.SCHEMATA contains the schemas. INFORMATION_SCHEMA.SCHEMATA contains the schemas.
INFORMATION_SCHEMA.SESSIONS contains the open sessions.
INFORMATION_SCHEMA.SEQUENCES contains the sequences. INFORMATION_SCHEMA.SEQUENCES contains the sequences.
INFORMATION_SCHEMA.SETTINGS contains the settings. INFORMATION_SCHEMA.SETTINGS contains the settings.
INFORMATION_SCHEMA.TABLES contains the tables. INFORMATION_SCHEMA.TABLES contains the tables.
......
...@@ -8,12 +8,14 @@ import java.io.IOException; ...@@ -8,12 +8,14 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
...@@ -55,10 +57,20 @@ public class TcpServer implements Service { ...@@ -55,10 +57,20 @@ public class TcpServer implements Service {
private boolean allowOthers; private boolean allowOthers;
private boolean ifExists; private boolean ifExists;
private Connection managementDb; private Connection managementDb;
private PreparedStatement managementDbAdd;
private PreparedStatement managementDbRemove;
private String managementPassword = ""; private String managementPassword = "";
private static HashMap servers = new HashMap(); private static final Map SERVERS = Collections.synchronizedMap(new HashMap());
private Thread listenerThread; private Thread listenerThread;
private int nextThreadId;
/**
* Get the database name of the management database.
* The management database contains a table with active sessions (SESSIONS).
*
* @param port the TCP server port
* @return the database name (usually starting with mem:)
*/
public static String getManagementDbName(int port) { public static String getManagementDbName(int port) {
return "mem:" + Constants.MANAGEMENT_DB_PREFIX + port; return "mem:" + Constants.MANAGEMENT_DB_PREFIX + port;
} }
...@@ -74,10 +86,47 @@ public class TcpServer implements Service { ...@@ -74,10 +86,47 @@ public class TcpServer implements Service {
try { try {
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("CREATE ALIAS IF NOT EXISTS STOP_SERVER FOR \"" + TcpServer.class.getName() + ".stopServer\""); stat.execute("CREATE ALIAS IF NOT EXISTS STOP_SERVER FOR \"" + TcpServer.class.getName() + ".stopServer\"");
stat.execute("CREATE TABLE IF NOT EXISTS SESSIONS(ID INT PRIMARY KEY, URL VARCHAR, USER VARCHAR, CONNECTED TIMESTAMP)");
managementDbAdd = conn.prepareStatement("INSERT INTO SESSIONS VALUES(?, ?, ?, NOW())");
managementDbRemove = conn.prepareStatement("DELETE FROM SESSIONS WHERE ID=?");
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
} }
servers.put("" + port, this); SERVERS.put("" + port, this);
}
/**
* Get the list of ports of all running TCP server.
*
* @return the list of ports
*/
public static int[] getAllServerPorts() {
Object[] servers = SERVERS.keySet().toArray();
int[] ports = new int[servers.length];
for (int i = 0; i < servers.length; i++) {
ports[i] = Integer.parseInt(servers[i].toString());
}
return ports;
}
synchronized void addConnection(int id, String url, String user) {
try {
managementDbAdd.setInt(1, id);
managementDbAdd.setString(2, url);
managementDbAdd.setString(3, user);
managementDbAdd.execute();
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
}
}
synchronized void removeConnection(int id) {
try {
managementDbRemove.setInt(1, id);
managementDbRemove.execute();
} catch (SQLException e) {
TraceSystem.traceThrowable(e);
}
} }
private void stopManagementDb() { private void stopManagementDb() {
...@@ -141,7 +190,7 @@ public class TcpServer implements Service { ...@@ -141,7 +190,7 @@ public class TcpServer implements Service {
try { try {
while (!stop) { while (!stop) {
Socket s = serverSocket.accept(); Socket s = serverSocket.accept();
TcpServerThread c = new TcpServerThread(s, this); TcpServerThread c = new TcpServerThread(s, this, nextThreadId++);
running.add(c); running.add(c);
Thread thread = new Thread(c); Thread thread = new Thread(c);
thread.setName(threadName + " thread"); thread.setName(threadName + " thread");
...@@ -202,11 +251,11 @@ public class TcpServer implements Service { ...@@ -202,11 +251,11 @@ public class TcpServer implements Service {
TraceSystem.traceThrowable(e); TraceSystem.traceThrowable(e);
} }
} }
servers.remove("" + port); SERVERS.remove("" + port);
} }
public static synchronized void stopServer(int port, String password, int shutdownMode) { public static synchronized void stopServer(int port, String password, int shutdownMode) {
TcpServer server = (TcpServer) servers.get("" + port); TcpServer server = (TcpServer) SERVERS.get("" + port);
if (server == null) { if (server == null) {
return; return;
} }
......
...@@ -39,9 +39,11 @@ public class TcpServerThread implements Runnable { ...@@ -39,9 +39,11 @@ public class TcpServerThread implements Runnable {
private Transfer transfer; private Transfer transfer;
private Command commit; private Command commit;
private SmallMap cache = new SmallMap(SysProperties.SERVER_CACHED_OBJECTS); private SmallMap cache = new SmallMap(SysProperties.SERVER_CACHED_OBJECTS);
private int id;
public TcpServerThread(Socket socket, TcpServer server) { public TcpServerThread(Socket socket, TcpServer server, int id) {
this.server = server; this.server = server;
this.id = id;
transfer = new Transfer(null); transfer = new Transfer(null);
transfer.setSocket(socket); transfer.setSocket(socket);
} }
...@@ -90,6 +92,7 @@ public class TcpServerThread implements Runnable { ...@@ -90,6 +92,7 @@ public class TcpServerThread implements Runnable {
session = engine.getSession(ci); session = engine.getSession(ci);
transfer.setSession(session); transfer.setSession(session);
transfer.writeInt(SessionRemote.STATUS_OK).flush(); transfer.writeInt(SessionRemote.STATUS_OK).flush();
server.addConnection(id, originalURL, ci.getUserName());
log("Connected"); log("Connected");
} catch (Throwable e) { } catch (Throwable e) {
sendError(e); sendError(e);
...@@ -116,6 +119,7 @@ public class TcpServerThread implements Runnable { ...@@ -116,6 +119,7 @@ public class TcpServerThread implements Runnable {
Command rollback = session.prepareLocal("ROLLBACK"); Command rollback = session.prepareLocal("ROLLBACK");
rollback.executeUpdate(); rollback.executeUpdate();
session.close(); session.close();
server.removeConnection(id);
} catch (Exception e) { } catch (Exception e) {
server.logError(e); server.logError(e);
} finally { } finally {
......
...@@ -12,6 +12,7 @@ import java.io.Reader; ...@@ -12,6 +12,7 @@ import java.io.Reader;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.Collator; import java.text.Collator;
import java.util.Locale; import java.util.Locale;
...@@ -66,7 +67,7 @@ public class MetaTable extends Table { ...@@ -66,7 +67,7 @@ public class MetaTable extends Table {
SETTINGS = 6, HELP = 7, SEQUENCES = 8, USERS = 9, ROLES = 10, RIGHTS = 11, FUNCTION_ALIASES = 12, SETTINGS = 6, HELP = 7, SEQUENCES = 8, USERS = 9, ROLES = 10, RIGHTS = 11, FUNCTION_ALIASES = 12,
SCHEMATA = 13, TABLE_PRIVILEGES = 14, COLUMN_PRIVILEGES = 15, COLLATIONS = 16, VIEWS = 17, IN_DOUBT = 18, SCHEMATA = 13, TABLE_PRIVILEGES = 14, COLUMN_PRIVILEGES = 15, COLLATIONS = 16, VIEWS = 17, IN_DOUBT = 18,
CROSS_REFERENCES = 19, CONSTRAINTS = 20, FUNCTION_COLUMNS = 21, CONSTANTS = 22, DOMAINS = 23, CROSS_REFERENCES = 19, CONSTRAINTS = 20, FUNCTION_COLUMNS = 21, CONSTANTS = 22, DOMAINS = 23,
TRIGGERS = 24; TRIGGERS = 24, SESSIONS = 25, LOCKS = 26;
private final int type; private final int type;
private final int indexColumn; private final int indexColumn;
...@@ -428,6 +429,26 @@ public class MetaTable extends Table { ...@@ -428,6 +429,26 @@ public class MetaTable extends Table {
"ID INT" "ID INT"
}); });
break; break;
case SESSIONS: {
setObjectName("SESSIONS");
cols = createColumns(new String[]{
"ID INT",
"USER_NAME",
"CURRENT_STATEMENT",
"LOGIN_TIME",
});
break;
}
case LOCKS: {
setObjectName("LOCKS");
cols = createColumns(new String[]{
"TABLE_SCHEMA",
"TABLE_NAME",
"SESSION_ID INT",
"LOCK_TYPE",
});
break;
}
default: default:
throw Message.getInternalError("type="+type); throw Message.getInternalError("type="+type);
} }
...@@ -1178,6 +1199,42 @@ public class MetaTable extends Table { ...@@ -1178,6 +1199,42 @@ public class MetaTable extends Table {
} }
break; break;
} }
case SESSIONS: {
Session[] sessions = database.getSessions();
boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
if (admin || s == session) {
add(rows, new String[] {
"" + s.getId(), // ID
s.getUser().getName(), // USER_NAME
s.getCurrentCommand(), // CURRENT_COMMAND
new Timestamp(s.getLoginTime()).toString(), // LOGIN_TIME
});
}
}
break;
}
case LOCKS: {
Session[] sessions = database.getSessions();
boolean admin = session.getUser().getAdmin();
for (int i = 0; i < sessions.length; i++) {
Session s = sessions[i];
if (admin || s == session) {
Table[] locks = s.getLocks();
for (int j = 0; j < locks.length; j++) {
Table table = locks[j];
add(rows, new String[] {
table.getSchema().getName(), // TABLE_SCHEMA
table.getName(), // TABLE_NAME
"" + s.getId(), // SESSION_ID
table.isLockExclusive(s) ? "WRITE" : "READ", // LOCK_TYPE
});
}
}
}
break;
}
default: default:
throw Message.getInternalError("type="+type); throw Message.getInternalError("type="+type);
} }
......
...@@ -135,6 +135,10 @@ public abstract class Table extends SchemaObjectBase { ...@@ -135,6 +135,10 @@ public abstract class Table extends SchemaObjectBase {
public abstract void lock(Session session, boolean exclusive, boolean force) throws SQLException; public abstract void lock(Session session, boolean exclusive, boolean force) throws SQLException;
public boolean isLockExclusive(Session s) {
return false;
}
public abstract void close(Session session) throws SQLException; public abstract void close(Session session) throws SQLException;
public abstract void unlock(Session s); public abstract void unlock(Session s);
......
...@@ -307,6 +307,10 @@ public class TableData extends Table implements RecordReader { ...@@ -307,6 +307,10 @@ public class TableData extends Table implements RecordReader {
rowCount = 0; rowCount = 0;
} }
public boolean isLockExclusive(Session s) {
return lockExclusive == s;
}
public void lock(Session session, boolean exclusive, boolean force) throws SQLException { public void lock(Session session, boolean exclusive, boolean force) throws SQLException {
int lockMode = database.getLockMode(); int lockMode = database.getLockMode();
if (lockMode == Constants.LOCK_MODE_OFF) { if (lockMode == Constants.LOCK_MODE_OFF) {
......
...@@ -630,4 +630,33 @@ public class StringUtils { ...@@ -630,4 +630,33 @@ public class StringUtils {
return sql; return sql;
} }
public static String pad(String string, int n, String padding, boolean right) {
if (n < 0) {
n = 0;
}
if (n < string.length()) {
return string.substring(0, n);
} else if (n == string.length()) {
return string;
}
char paddingChar;
if (padding == null || padding.length() == 0) {
paddingChar = ' ';
} else {
paddingChar = padding.charAt(0);
}
StringBuffer buff = new StringBuffer(n);
n -= string.length();
if (right) {
buff.append(string);
}
for (int i = 0; i < n; i++) {
buff.append(paddingChar);
}
if (!right) {
buff.append(string);
}
return buff.toString();
}
} }
...@@ -151,10 +151,8 @@ java org.h2.test.TestAll timer ...@@ -151,10 +151,8 @@ java org.h2.test.TestAll timer
/* /*
History: write simple test for
The Ukrainian translation was not working in the last release. Fixed. NFORMATION_SCHEMA.SESSIONS and LOCKS
Creating many tables (many hundreds) was slow. Fixed.
Opening a database with many indexes (thousands) was slow. Fixed.
C:\temp\test\db C:\temp\test\db
......
...@@ -96,6 +96,8 @@ public class TestMetaData extends TestBase { ...@@ -96,6 +96,8 @@ public class TestMetaData extends TestBase {
rs.next(); rs.next();
check("IN_DOUBT", rs.getString("TABLE_NAME")); check("IN_DOUBT", rs.getString("TABLE_NAME"));
rs.next(); rs.next();
check("LOCKS", rs.getString("TABLE_NAME"));
rs.next();
check("RIGHTS", rs.getString("TABLE_NAME")); check("RIGHTS", rs.getString("TABLE_NAME"));
rs.next(); rs.next();
check("ROLES", rs.getString("TABLE_NAME")); check("ROLES", rs.getString("TABLE_NAME"));
...@@ -104,6 +106,8 @@ public class TestMetaData extends TestBase { ...@@ -104,6 +106,8 @@ public class TestMetaData extends TestBase {
rs.next(); rs.next();
check("SEQUENCES", rs.getString("TABLE_NAME")); check("SEQUENCES", rs.getString("TABLE_NAME"));
rs.next(); rs.next();
check("SESSIONS", rs.getString("TABLE_NAME"));
rs.next();
check("SETTINGS", rs.getString("TABLE_NAME")); check("SETTINGS", rs.getString("TABLE_NAME"));
rs.next(); rs.next();
check("TABLES", rs.getString("TABLE_NAME")); check("TABLES", rs.getString("TABLE_NAME"));
......
...@@ -362,6 +362,9 @@ public class TestCrashAPI extends TestBase { ...@@ -362,6 +362,9 @@ public class TestCrashAPI extends TestBase {
public TestBase init(TestAll conf) throws Exception { public TestBase init(TestAll conf) throws Exception {
super.init(conf); super.init(conf);
if (config.mvcc) {
return this;
}
if (config.logMode == 0) { if (config.logMode == 0) {
error("Log mode 0 may corrupt the db, can't test"); error("Log mode 0 may corrupt the db, can't test");
} }
...@@ -382,6 +385,9 @@ public class TestCrashAPI extends TestBase { ...@@ -382,6 +385,9 @@ public class TestCrashAPI extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
if (config.mvcc) {
return;
}
int len = getSize(2, 6); int len = getSize(2, 6);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
int seed = RandomUtils.nextInt(Integer.MAX_VALUE); int seed = RandomUtils.nextInt(Integer.MAX_VALUE);
......
select lpad('string', 10, '+');
> ++++string;
select rpad('string', 10, '+');
> string++++;
select lpad('string', 10);
> string;
select count(*) from (select * from dual union select * from dual) where x = 0; select count(*) from (select * from dual union select * from dual) where x = 0;
> 0; > 0;
select count(*) from (select * from (select * from dual union select * from dual)) where x = 0; select count(*) from (select * from (select * from dual union select * from dual)) where x = 0;
......
...@@ -19,6 +19,14 @@ public class TestStringUtils extends TestBase { ...@@ -19,6 +19,14 @@ public class TestStringUtils extends TestBase {
testSplit(); testSplit();
testJavaString(); testJavaString();
testURL(); testURL();
testPad();
}
private void testPad() throws Exception {
check("large", StringUtils.pad("larger text", 5, null, true));
check("large", StringUtils.pad("larger text", 5, null, false));
check("short+++++", StringUtils.pad("short", 10, "+", true));
check("+++++short", StringUtils.pad("short", 10, "+", false));
} }
private void testXML() throws Exception { private void testXML() throws Exception {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论