提交 7e13d7de authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 b2fbde08
...@@ -40,7 +40,9 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -40,7 +40,9 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0.59 (2007-09-TODO)</h3><ul> <h3>Version 1.0.59 (2007-09-TODO)</h3><ul>
<li>When creating a table using CREATE TABLE .. AS SELECT, the precision for some data types (for example VARCHAR) <li>Fulltext search is now documented (in the Tutorial).
</li><li>The Console did not refresh the table list if the CREATE TABLE statement started with a comment. Fixed.
</li><li>When creating a table using CREATE TABLE .. AS SELECT, the precision for some data types (for example VARCHAR)
was set to the default precision. Fixed. was set to the default precision. Fixed.
</li><li>When using the (undocumented) in-memory file system (jdbc:h2:memFS:x or jdbc:h2:memLZF:x), and using </li><li>When using the (undocumented) in-memory file system (jdbc:h2:memFS:x or jdbc:h2:memLZF:x), and using
multiple connections, a ConcurrentModificationException could occur. Fixed. multiple connections, a ConcurrentModificationException could occur. Fixed.
...@@ -506,6 +508,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -506,6 +508,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Optimization: automatic index creation suggestion using the trace file? </li><li>Optimization: automatic index creation suggestion using the trace file?
</li><li>Compression performance: don't allocate buffers, compress / expand in to out buffer </li><li>Compression performance: don't allocate buffers, compress / expand in to out buffer
</li><li>Connection pool manager </li><li>Connection pool manager
</li><li>Implement Statement.cancel for server connections
</li><li>Start / stop server with database URL </li><li>Start / stop server with database URL
</li><li>Rebuild index functionality (other than delete the index file) </li><li>Rebuild index functionality (other than delete the index file)
</li><li>Don't use deleteOnExit (bug 4513817: File.deleteOnExit consumes memory) </li><li>Don't use deleteOnExit (bug 4513817: File.deleteOnExit consumes memory)
...@@ -563,7 +566,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -563,7 +566,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Test http://mysql-je.sourceforge.net/ </li><li>Test http://mysql-je.sourceforge.net/
</li><li>Close all files when closing the database (including LOB files that are open on the client side) </li><li>Close all files when closing the database (including LOB files that are open on the client side)
</li><li>Test Connection Pool http://jakarta.apache.org/commons/dbcp </li><li>Test Connection Pool http://jakarta.apache.org/commons/dbcp
</li><li>Implement Statement.cancel for server connections
</li><li>Profiler option or profiling tool to find long running and often repeated queries (using DatabaseEventListener API) </li><li>Profiler option or profiling tool to find long running and often repeated queries (using DatabaseEventListener API)
</li><li>Function to read/write a file from/to LOB </li><li>Function to read/write a file from/to LOB
</li><li>Allow custom settings (@PATH for RUNSCRIPT for example) </li><li>Allow custom settings (@PATH for RUNSCRIPT for example)
...@@ -774,6 +776,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -774,6 +776,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Server: use one listener (detect if the request comes from an PG or TCP client) </li><li>Server: use one listener (detect if the request comes from an PG or TCP client)
</li><li>Store dates as 'local'. Existing files use GMT. Use escape syntax for compatibility) </li><li>Store dates as 'local'. Existing files use GMT. Use escape syntax for compatibility)
</li><li>Support data type INTERVAL </li><li>Support data type INTERVAL
</li><li>NATURAL JOIN: MySQL and PostgreSQL don't repeat columns when using SELECT * ...
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -32,6 +32,8 @@ Tutorial ...@@ -32,6 +32,8 @@ Tutorial
Using OpenOffice Base</a><br /> Using OpenOffice Base</a><br />
<a href="#web_start"> <a href="#web_start">
Java Web Start / JNLP</a><br /> Java Web Start / JNLP</a><br />
<a href="#fulltext">
Fulltext Search</a><br />
<br /><a name="tutorial_starting_h2_console"></a> <br /><a name="tutorial_starting_h2_console"></a>
<h2>Starting and Using the H2 Console</h2> <h2>Starting and Using the H2 Console</h2>
...@@ -518,4 +520,72 @@ Example permission tags: ...@@ -518,4 +520,72 @@ Example permission tags:
</pre> </pre>
</p> </p>
<br /><a name="fulltext"></a>
<h2>Fulltext Search</h2>
<p>
H2 supports Lucene full text search and native full text search implementation.
</p>
<h3>Using the Native Full Text Search</h3>
<p>
To initialize, call:
<p>
<pre>
CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init";
CALL FT_INIT();
</pre>
<p>
Afterwards, you can create a full text index for a table using:
</p>
<pre>
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FT_CREATE_INDEX('PUBLIC', 'TEST', NULL);
</pre>
<p>
PUBLIC is the schema, TEST is the table name. The list of column names (column separated) is optional,
in this case all columns are indexed. The index is updated in read time.
To search the index, use the following query:
</p>
<pre>
SELECT * FROM FT_SEARCH('Hello', 0, 0);
</pre>
<p>
You can also call the index from within a Java application:
</p>
<pre>
org.h2.fulltext.FullText.search(conn, text, limit, offset)
</pre>
<h3>Using the Lucene Fulltext Search</h3>
<p>
To use the Lucene full text search, you first need to rename the file FullTextLucene.java.txt to FullTestLucene.java and compile it. Also, you need the Lucene library in the classpath.
To initialize, call:
</p>
<pre>
CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init";
CALL FTL_INIT();
</pre>
<p>
Afterwards, you can create a full text index for a table using:
</p>
<pre>
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL);
</pre>
<p>
PUBLIC is the schema, TEST is the table name. The list of column names (column separated) is optional,
in this case all columns are indexed. The index is updated in read time. To search the index, use the following query:
</p>
<pre>
SELECT * FROM FTL_SEARCH('Hello', 0, 0);
</pre>
<p>
You can also call the index from within a Java application:
</p>
<pre>
org.h2.fulltext.FullTextLucene.search(conn, text, limit, offset)
</pre>
</div></td></tr></table></body></html> </div></td></tr></table></body></html>
\ No newline at end of file
...@@ -42,7 +42,7 @@ public class ConnectionInfo { ...@@ -42,7 +42,7 @@ public class ConnectionInfo {
// TODO document these settings // TODO document these settings
String[] connectionTime = new String[] { "ACCESS_MODE_LOG", "ACCESS_MODE_DATA", "AUTOCOMMIT", "CIPHER", String[] connectionTime = new String[] { "ACCESS_MODE_LOG", "ACCESS_MODE_DATA", "AUTOCOMMIT", "CIPHER",
"CREATE", "CACHE_TYPE", "DB_CLOSE_ON_EXIT", "FILE_LOCK", "IGNORE_UNKNOWN_SETTINGS", "IFEXISTS", "CREATE", "CACHE_TYPE", "DB_CLOSE_ON_EXIT", "FILE_LOCK", "IGNORE_UNKNOWN_SETTINGS", "IFEXISTS",
"PASSWORD", "RECOVER", "STORAGE", "USER", "MVCC" }; "PASSWORD", "RECOVER", "STORAGE", "USER", "MVCC", "DATABASE_EVENT_LISTENER_OBJECT" };
for (int i = 0; i < connectionTime.length; i++) { for (int i = 0; i < connectionTime.length; i++) {
String key = connectionTime[i]; String key = connectionTime[i];
if (SysProperties.CHECK && KNOWN_SETTINGS.contains(key)) { if (SysProperties.CHECK && KNOWN_SETTINGS.contains(key)) {
......
...@@ -11,6 +11,7 @@ import java.net.ServerSocket; ...@@ -11,6 +11,7 @@ import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
...@@ -77,6 +78,7 @@ public class WebServer implements Service { ...@@ -77,6 +78,7 @@ public class WebServer implements Service {
private static int ticker; private static int ticker;
private int port; private int port;
private boolean allowOthers; private boolean allowOthers;
private HashSet running = new HashSet();
private boolean ssl; private boolean ssl;
private HashMap connInfoMap = new HashMap(); private HashMap connInfoMap = new HashMap();
...@@ -114,6 +116,10 @@ public class WebServer implements Service { ...@@ -114,6 +116,10 @@ public class WebServer implements Service {
return new String(bytes); return new String(bytes);
} }
synchronized void remove(WebThread t) {
running.remove(t);
}
private String generateSessionId() { private String generateSessionId() {
byte[] buff = RandomUtils.getSecureBytes(16); byte[] buff = RandomUtils.getSecureBytes(16);
return ByteUtils.convertBytesToString(buff); return ByteUtils.convertBytesToString(buff);
...@@ -217,6 +223,7 @@ public class WebServer implements Service { ...@@ -217,6 +223,7 @@ public class WebServer implements Service {
while (serverSocket != null) { while (serverSocket != null) {
Socket s = serverSocket.accept(); Socket s = serverSocket.accept();
WebThread c = new WebThread(s, this); WebThread c = new WebThread(s, this);
running.add(c);
c.start(); c.start();
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -251,6 +258,30 @@ public class WebServer implements Service { ...@@ -251,6 +258,30 @@ public class WebServer implements Service {
TraceSystem.traceThrowable(e); TraceSystem.traceThrowable(e);
} }
} }
// TODO server: using a boolean 'now' argument? a timeout?
ArrayList list = new ArrayList(sessions.values());
for (int i = 0; i < list.size(); i++) {
WebSession session = (WebSession) list.get(i);
Statement stat = session.executingStatement;
if (stat != null) {
try {
stat.cancel();
} catch (Exception e) {
// ignore
}
}
}
list = new ArrayList(running);
for (int i = 0; i < list.size(); i++) {
WebThread c = (WebThread) list.get(i);
try {
c.stopNow();
c.join(100);
} catch (Exception e) {
// TODO log exception
e.printStackTrace();
}
}
} }
void trace(String s) { void trace(String s) {
......
...@@ -56,6 +56,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -56,6 +56,7 @@ class WebThread extends Thread implements DatabaseEventListener {
private boolean cache; private boolean cache;
private int listenerLastState; private int listenerLastState;
private long listenerLastEvent; private long listenerLastEvent;
private boolean stop;
// TODO web: support online data editing like http://numsum.com/ // TODO web: support online data editing like http://numsum.com/
...@@ -70,6 +71,10 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -70,6 +71,10 @@ class WebThread extends Thread implements DatabaseEventListener {
this.attributes = attributes; this.attributes = attributes;
} }
public void stopNow() {
this.stop = true;
}
private String getAllowedFile(String requestedFile) { private String getAllowedFile(String requestedFile) {
if (!allow()) { if (!allow()) {
return "notAllowed.jsp"; return "notAllowed.jsp";
...@@ -188,6 +193,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -188,6 +193,7 @@ class WebThread extends Thread implements DatabaseEventListener {
output.flush(); output.flush();
output.close(); output.close();
socket.close(); socket.close();
server.remove(this);
return; return;
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -1183,8 +1189,8 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1183,8 +1189,8 @@ class WebThread extends Thread implements DatabaseEventListener {
sql = sql.trim(); sql = sql.trim();
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
String sqlUpper = StringUtils.toUpperEnglish(sql); String sqlUpper = StringUtils.toUpperEnglish(sql);
if (sqlUpper.startsWith("CREATE") || sqlUpper.startsWith("DROP") || sqlUpper.startsWith("ALTER") if (sqlUpper.indexOf("CREATE") >= 0 || sqlUpper.indexOf("DROP") >= 0 || sqlUpper.indexOf("ALTER") >= 0
|| sqlUpper.startsWith("RUNSCRIPT")) { || sqlUpper.indexOf("RUNSCRIPT") >= 0) {
String sessionId = attributes.getProperty("jsessionid"); String sessionId = attributes.getProperty("jsessionid");
buff.append("<script type=\"text/javascript\">top['h2menu'].location='tables.do?jsessionid=" buff.append("<script type=\"text/javascript\">top['h2menu'].location='tables.do?jsessionid="
+ sessionId + "';</script>"); + sessionId + "';</script>");
...@@ -1282,7 +1288,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1282,7 +1288,7 @@ class WebThread extends Thread implements DatabaseEventListener {
private String executeLoop(Connection conn, int count, String sql) throws SQLException { private String executeLoop(Connection conn, int count, String sql) throws SQLException {
ArrayList params = new ArrayList(); ArrayList params = new ArrayList();
int idx = 0; int idx = 0;
while (true) { while (!stop) {
idx = sql.indexOf('?', idx); idx = sql.indexOf('?', idx);
if (idx < 0) { if (idx < 0) {
break; break;
...@@ -1303,7 +1309,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1303,7 +1309,7 @@ class WebThread extends Thread implements DatabaseEventListener {
sql = sql.substring("@STATEMENT".length()).trim(); sql = sql.substring("@STATEMENT".length()).trim();
prepared = false; prepared = false;
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
for (int i = 0; i < count; i++) { for (int i = 0; !stop && i < count; i++) {
String s = sql; String s = sql;
for (int j = 0; j < params.size(); j++) { for (int j = 0; j < params.size(); j++) {
idx = s.indexOf('?'); idx = s.indexOf('?');
...@@ -1316,7 +1322,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1316,7 +1322,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
if (stat.execute(s)) { if (stat.execute(s)) {
ResultSet rs = stat.getResultSet(); ResultSet rs = stat.getResultSet();
while (rs.next()) { while (!stop && rs.next()) {
rows++; rows++;
// maybe get the data as well // maybe get the data as well
} }
...@@ -1327,7 +1333,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1327,7 +1333,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} else { } else {
prepared = true; prepared = true;
PreparedStatement prep = conn.prepareStatement(sql); PreparedStatement prep = conn.prepareStatement(sql);
for (int i = 0; i < count; i++) { for (int i = 0; !stop && i < count; i++) {
for (int j = 0; j < params.size(); j++) { for (int j = 0; j < params.size(); j++) {
Integer type = (Integer) params.get(j); Integer type = (Integer) params.get(j);
if (type.intValue() == 1) { if (type.intValue() == 1) {
...@@ -1342,7 +1348,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1342,7 +1348,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} else { } else {
if (prep.execute()) { if (prep.execute()) {
ResultSet rs = prep.getResultSet(); ResultSet rs = prep.getResultSet();
while (rs.next()) { while (!stop && rs.next()) {
rows++; rows++;
// maybe get the data as well // maybe get the data as well
} }
...@@ -1603,16 +1609,16 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1603,16 +1609,16 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
switch(state) { switch(state) {
case DatabaseEventListener.STATE_BACKUP_FILE: case DatabaseEventListener.STATE_BACKUP_FILE:
log("Backing up " + name + " " + (100L * max / x) + "%"); log("Backing up " + name + " " + (100L * x / max) + "%");
break; break;
case DatabaseEventListener.STATE_CREATE_INDEX: case DatabaseEventListener.STATE_CREATE_INDEX:
log("Creating index " + name + " " + (100L * max / x) + "%"); log("Creating index " + name + " " + (100L * x / max) + "%");
break; break;
case DatabaseEventListener.STATE_RECOVER: case DatabaseEventListener.STATE_RECOVER:
log("Recovering " + name + " " + (100L * max / x) + "%"); log("Recovering " + name + " " + (100L * x / max) + "%");
break; break;
case DatabaseEventListener.STATE_SCAN_FILE: case DatabaseEventListener.STATE_SCAN_FILE:
log("Scanning file " + name + " " + (100L * max / x) + "%"); log("Scanning file " + name + " " + (100L * x / max) + "%");
break; break;
default: default:
log("Unknown state: " + state); log("Unknown state: " + state);
......
...@@ -48,7 +48,7 @@ import org.h2.test.db.TestTwoPhaseCommit; ...@@ -48,7 +48,7 @@ import org.h2.test.db.TestTwoPhaseCommit;
import org.h2.test.db.TestView; import org.h2.test.db.TestView;
import org.h2.test.jdbc.TestCancel; import org.h2.test.jdbc.TestCancel;
import org.h2.test.jdbc.TestDataSource; import org.h2.test.jdbc.TestDataSource;
//import org.h2.test.jdbc.TestDatabaseEventListener; import org.h2.test.jdbc.TestDatabaseEventListener;
import org.h2.test.jdbc.TestManyJdbcObjects; import org.h2.test.jdbc.TestManyJdbcObjects;
import org.h2.test.jdbc.TestMetaData; import org.h2.test.jdbc.TestMetaData;
import org.h2.test.jdbc.TestNativeSQL; import org.h2.test.jdbc.TestNativeSQL;
...@@ -144,85 +144,21 @@ java org.h2.test.TestAll timer ...@@ -144,85 +144,21 @@ java org.h2.test.TestAll timer
/* /*
exit console doesn't always work any more
web page translation web page translation
Full Text Search
H2 supports Lucene full text search and native full text search implementation.
Using the Native Full Text Search
To initialize, call:
CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init";
CALL FT_INIT();
Afterwards, you can create a full text index for a table using:
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FT_CREATE_INDEX('PUBLIC', 'TEST', NULL);
where PUBLIC is the schema, TEST is the table name. The list of column names (column separated) is optional, in this case all columns are indexed. The index is updated in read time. To search the index, use the following query:
SELECT * FROM FT_SEARCH('Hello', 0, 0);
You can also call the index from within a Java application:
org.h2.fulltext.FullText.search(conn, text, limit, offset)
Using the Lucene Full Text Search
To use the Lucene full text search, you first need to rename the file FullTextLucene.java.txt to FullTestLucene.java and compile it. Also, you need the Lucene library in the classpath.
To initialize, call:
CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init";
CALL FTL_INIT();
Afterwards, you can create a full text index for a table using:
CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL);
where PUBLIC is the schema, TEST is the table name. The list of column names (column separated) is optional, in this case all columns are indexed. The index is updated in read time. To search the index, use the following query:
SELECT * FROM FTL_SEARCH('Hello', 0, 0);
You can also call the index from within a Java application:
org.h2.fulltext.FullTextLucene.search(conn, text, limit, offset)
create table test(id int, name varchar(255));
SELECT * FROM TEST a natural JOIN TEST b;
drop table test;
H2:
ID, NAME, ID, NAME
MySQL, PostgreSQL:
ID, NAME
Derby, HSQLDB, MS SQL Server:
no supported
H2 supports cancel for the embedded mode but not yet for the client / server mode. I will add a feature request for this.
set log 0; set log 0;
drop table test;
create table test(id int primary key, name varchar); create table test(id int primary key, name varchar);
@LOOP 10000 insert into test values(?, space(100000)); @LOOP 100000 insert into test values(?, space(1000));
shutdown; shutdown;
a SHUTDOWN command is not enough? > a SHUTDOWN command is not enough? >
No, currently SHUTDOWN will not correctly close the objects if LOG is set to 0. No, currently SHUTDOWN will not correctly close the objects if LOG is set to 0.
It _should_ be enough however. I will change the code so that in the future SHUTDOWN will be enough, and regular database closing will be enough. It _should_ be enough however. I will change the code so that in the future SHUTDOWN will be enough, and regular database closing will be enough.
run benchmark with newest version of apache derby and hsqldb run benchmark with newest version of apache derby and hsqldb
TestMultiThreadedKernel and integrate in unit tests; use also in-memory and so on TestMultiThreadedKernel and integrate in unit tests; use also in-memory and so on
Sorry.... I just read the doc and it says using LOG=0 can lead to Sorry.... I just read the doc and it says using LOG=0 can lead to
corruption... corruption...
......
/*
* 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.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.api.DatabaseEventListener;
import org.h2.test.TestBase;
public class TestDatabaseEventListener extends TestBase implements DatabaseEventListener {
private boolean calledOpened, calledClosingDatabase;
public void test() throws Exception {
Properties p = new Properties();
p.setProperty("user", "sa");
p.setProperty("password", "sa");
TestDatabaseEventListener l = new TestDatabaseEventListener();
p.put("DATABASE_EVENT_LISTENER_OBJECT", l);
org.h2.Driver.load();
Connection conn = DriverManager.getConnection("jdbc:h2:mem:databaseEventListener", p);
conn.close();
check(l.calledOpened);
check(l.calledClosingDatabase);
}
public void closingDatabase() {
calledClosingDatabase = true;
}
public void diskSpaceIsLow(long stillAvailable) throws SQLException {
}
public void exceptionThrown(SQLException e, String sql) {
}
public void init(String url) {
}
public void opened() {
calledOpened = true;
}
public void setProgress(int state, String name, int x, int max) {
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论