提交 783321d4 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 7e13d7de
......@@ -235,7 +235,7 @@
<javadoc
sourcepath="src/main"
packagenames="org.h2.jdbc.*,org.h2.tools.*,org.h2.api.*,org.h2.store.*"
destDir="doc/javadoc"
destDir="docs/javadocImpl"
/> <!-- doclet="org.h2.tools.doclet.Doclet" docletpath="bin"-->
<copy todir="docs/javadoc">
<fileset dir="src/docsrc/javadoc" includes="**/*"/>
......
......@@ -40,16 +40,19 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3>
<h3>Version 1.0.59 (2007-09-TODO)</h3><ul>
<li>Fulltext search is now documented (in the Tutorial).
<li>A PreparedStatement that was cancelled could not be reused. Fixed.
</li><li>H2 Console: Progress information when logging into a H2 embedded database (useful when opening a database is slow).
</li><li>When the database was closed while logging was disabled (LOG 0), re-opening the database was slow. Fixed.
</li><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
multiple connections, a ConcurrentModificationException could occur. Fixed.
multiple connections, a ConcurrentModificationException could occur. Fixed.
</li><li>REGEXP compatibility: So far String.matches was used, but for compatibility with MySQL, now Matcher.find is used.
</li><li>SCRIPT: the SQL statements in the result set now include the terminating semicolon as well. Simplifies copy and paste.
</li><li>When using a subquery with group by as a table, some columns could not be used in the where condition
in the outer query. Example: SELECT * FROM (SELECT ID, COUNT(*) C FROM TEST) WHERE C > 100. Fixed.
in the outer query. Example: SELECT * FROM (SELECT ID, COUNT(*) C FROM TEST) WHERE C > 100. Fixed.
</li><li>Views with subqueries as tables and queries with nested subqueries as tables did not always work. Fixed.
</li><li>Compatibility: comparing columns with constants that are out of range does not throw an exception.
</li></ul>
......@@ -777,6 +780,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Store dates as 'local'. Existing files use GMT. Use escape syntax for compatibility)
</li><li>Support data type INTERVAL
</li><li>NATURAL JOIN: MySQL and PostgreSQL don't repeat columns when using SELECT * ...
</li><li>Optimize SELECT MIN(ID), MAX(ID), COUNT(*) FROM TEST WHERE ID BETWEEN 100 AND 200
</li><li>Support Oracle functions: TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER
</li></ul>
<h3>Not Planned</h3>
......
......@@ -529,7 +529,7 @@ H2 supports Lucene full text search and native full text search implementation.
<h3>Using the Native Full Text Search</h3>
<p>
To initialize, call:
<p>
</p>
<pre>
CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init";
CALL FT_INIT();
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -85,6 +85,7 @@ public abstract class Command implements CommandInterface {
public void checkCancelled() throws SQLException {
if (cancel) {
cancel = false;
throw Message.getSQLException(ErrorCode.STATEMENT_WAS_CANCELLED);
}
session.throttle();
......
......@@ -9,6 +9,7 @@ import java.sql.SQLException;
import org.h2.command.Prepared;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.log.LogSystem;
import org.h2.message.Message;
import org.h2.result.LocalResult;
......@@ -112,7 +113,9 @@ public class TransactionCommand extends Prepared {
s.close();
}
}
db.getLog().checkpoint();
LogSystem log = db.getLog();
log.setDisabled(false);
log.checkpoint();
session.close();
break;
}
......
......@@ -306,7 +306,10 @@ public class ConnectionInfo {
}
public void setProperty(String key, String value) {
prop.setProperty(key, value);
// value is null if the value is an object
if (value != null) {
prop.setProperty(key, value);
}
}
public String getURL() {
......
......@@ -801,6 +801,9 @@ public class Database implements DataHandler {
}
}
}
if (log != null) {
log.setDisabled(false);
}
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName);
if (eventListener != null) {
// allow the event listener to connect to the database
......
......@@ -73,7 +73,22 @@ public class TableLink extends Table {
int i = 0;
ObjectArray columnList = new ObjectArray();
HashMap columnMap = new HashMap();
String catalog = null, schema = null;
while (rs.next()) {
String thisCatalog = rs.getString("TABLE_CAT");
if (catalog == null) {
catalog = thisCatalog;
}
String thisSchema = rs.getString("TABLE_SCHEM");
if (schema == null) {
schema = thisSchema;
}
if (!catalog.equals(thisCatalog) || !schema.equals(thisSchema)) {
// if the table exists in multiple schemas or tables, use the alternative solution
columnMap.clear();
columnList.clear();
break;
}
String n = rs.getString("COLUMN_NAME");
if (storesLowerCase && n.equals(StringUtils.toLowerEnglish(n))) {
n = StringUtils.toUpperEnglish(n);
......@@ -87,6 +102,7 @@ public class TableLink extends Table {
columnList.add(col);
columnMap.put(n, col);
}
// alternative solution
if (columnList.size() == 0) {
Statement stat = null;
try {
......
......@@ -4,6 +4,7 @@
*/
package org.h2.test;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;
......@@ -144,25 +145,36 @@ java org.h2.test.TestAll timer
/*
web page translation
set log 0;
drop table test;
create table test(id int primary key, name varchar);
@LOOP 100000 insert into test values(?, space(1000));
shutdown;
a SHUTDOWN command is not enough? >
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.
Thanks for the response. Yes I'm doing embedded so this is fine for
me. One other question, I have noticed that once I cancel my
PreparedStatement, it does not seem to work again. I couldn't find a
way to clear it, so I guess I have to re-instantiate it?
run benchmark with newest version of apache derby and hsqldb
Also, how promptly should this cancel take effect? It seemed to be
fairly delayed, but there's still a chance my implementation wasn't
correct.
TestMultiThreadedKernel and integrate in unit tests; use also in-memory and so on
Hi,
You are right, a PreparedStatement could not be reused after cancel was called.
I have fixed this and added a test case. Thanks for reporting this!
Sorry.... I just read the doc and it says using LOG=0 can lead to
corruption...
Delayed cancel: if you use the database in embedded mode, it depends on thread
scheduling when the statement is cancelled (you need two threads). I also got
this problem. What I did is use Thread.yield in my test, like this:
CREATE ALIAS YIELD FOR "java.lang.Thread.yield";
SELECT YIELD() FROM ...
So for each row, Thread.yield() is called, letting other threads do some work.
Another solution would be to use SET THROTTLE (see docs).
"At startup, when corrupted, say if LOG=0 was used before"
Thomas
web page translation
TestMultiThreadedKernel and integrate in unit tests; use also in-memory and so on
At startup, when corrupted, say if LOG=0 was used before
add MVCC
......@@ -254,9 +266,6 @@ translated .pdf
write tests using the PostgreSQL JDBC driver
support Oracle functions:
TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER;
*/
// run TestHalt
......@@ -561,7 +570,7 @@ TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER;
// jdbc
new TestCancel().runTest(this);
// new TestDatabaseEventListener().runTest(this);
new TestDatabaseEventListener().runTest(this);
new TestDataSource().runTest(this);
new TestManyJdbcObjects().runTest(this);
new TestMetaData().runTest(this);
......
......@@ -22,6 +22,30 @@ public class TestLinkedTable extends TestBase {
testLinkSchema();
testLinkEmitUpdates();
testLinkTable();
testLinkTwoTables();
}
private void testLinkTwoTables() throws Exception {
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:mem:one", "linkuser", "linkpass");
Statement stat = conn.createStatement();
stat.execute("CREATE SCHEMA Y");
stat.execute("CREATE TABLE A( C INT)");
stat.execute("INSERT INTO A VALUES(1)");
stat.execute("CREATE TABLE Y.A (C INT)");
stat.execute("INSERT INTO Y.A VALUES(2)");
Connection conn2 = DriverManager.getConnection("jdbc:h2:mem:two");
Statement stat2 = conn2.createStatement();
stat2.execute("CREATE LINKED TABLE one('org.h2.Driver', 'jdbc:h2:mem:one', 'linkuser', 'linkpass', 'Y.A');");
stat2.execute("CREATE LINKED TABLE two('org.h2.Driver', 'jdbc:h2:mem:one', 'linkuser', 'linkpass', 'A');");
ResultSet rs = stat2.executeQuery("SELECT * FROM one");
rs.next();
check(rs.getInt(1), 2);
rs = stat2.executeQuery("SELECT * FROM two");
rs.next();
check(rs.getInt(1), 1);
conn.close();
conn2.close();
}
private void testLinkDrop() throws Exception {
......
......@@ -7,6 +7,7 @@ package org.h2.test.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.h2.api.DatabaseEventListener;
......@@ -14,9 +15,45 @@ import org.h2.test.TestBase;
public class TestDatabaseEventListener extends TestBase implements DatabaseEventListener {
private boolean calledOpened, calledClosingDatabase;
private boolean calledOpened, calledClosingDatabase, calledScan;
public void test() throws Exception {
testCalled();
testCloseLog0(false);
testCloseLog0(true);
}
private void testCloseLog0(boolean shutdown) throws Exception {
if (config.memory) {
return;
}
deleteDb("databaseEventListener");
String url = getURL("databaseEventListener", true);
String user = getUser(), password = getPassword();
Properties p = new Properties();
p.setProperty("user", user);
p.setProperty("password", password);
Connection conn = DriverManager.getConnection(url, p);
Statement stat = conn.createStatement();
stat.execute("set log 0");
stat.execute("create table test(id int primary key, name varchar)");
stat.execute("insert into test select x, space(1000) from system_range(1,1000)");
if (shutdown) {
stat.execute("shutdown");
}
conn.close();
TestDatabaseEventListener l = new TestDatabaseEventListener();
p.put("DATABASE_EVENT_LISTENER_OBJECT", l);
org.h2.Driver.load();
conn = DriverManager.getConnection(url, p);
conn.close();
if (l.calledOpened) {
check(!l.calledScan);
}
}
private void testCalled() throws Exception {
Properties p = new Properties();
p.setProperty("user", "sa");
p.setProperty("password", "sa");
......@@ -47,6 +84,9 @@ public class TestDatabaseEventListener extends TestBase implements DatabaseEvent
}
public void setProgress(int state, String name, int x, int max) {
if (state == DatabaseEventListener.STATE_SCAN_FILE) {
calledScan = true;
}
}
}
......@@ -28,6 +28,7 @@ public class TestPreparedStatement extends TestBase {
deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement");
testCancelReuse(conn);
testCoalesce(conn);
testPreparedStatementMetaData(conn);
testDate(conn);
......@@ -49,6 +50,33 @@ public class TestPreparedStatement extends TestBase {
conn.close();
}
private void testCancelReuse(Connection conn) throws Exception {
conn.createStatement().execute("CREATE ALIAS YIELD FOR \"java.lang.Thread.yield\"");
final PreparedStatement prep = conn.prepareStatement("SELECT YIELD() FROM SYSTEM_RANGE(1, 1000000) LIMIT ?");
prep.setInt(1, 100000000);
Thread t = new Thread() {
public void run() {
try {
prep.execute();
} catch (SQLException e) {
// ignore
}
}
};
t.start();
Thread.sleep(10);
try {
prep.cancel();
} catch (SQLException e) {
this.checkNotGeneralException(e);
}
prep.setInt(1, 1);
ResultSet rs = prep.executeQuery();
check(rs.next());
check(rs.getInt(1), 0);
checkFalse(rs.next());
}
private void testCoalesce(Connection conn) throws Exception {
Statement stat = conn.createStatement();
stat.executeUpdate("create table test(tm timestamp)");
......
......@@ -21,14 +21,14 @@ create table multi_pages(dir_num int, bh_id int);
insert into multi_pages values(1, 1), (2, 2), (3, 3);
> update count: 3
create table bib_holdings(id int primary key, site varchar(255));
create table b_holding(id int primary key, site varchar(255));
> ok
insert into bib_holdings values(1, 'WSTIAC'), (2, 'WSTIAC'), (3, 'WSTIAC');
insert into b_holding values(1, 'Hello'), (2, 'Hello'), (3, 'Hello');
> update count: 3
select * from (select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh
where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num) as x
select * from (select dir_num, count(*) as cnt from multi_pages t, b_holding bh
where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc;
> DIR_NUM CNT
> ------- ---
......@@ -37,16 +37,16 @@ where cnt < 1000 order by dir_num asc;
> 3 1
> rows (ordered): 3
explain select * from (select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh
where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num) as x
explain select * from (select dir_num, count(*) as cnt from multi_pages t, b_holding bh
where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc;
> PLAN
> --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT X.DIR_NUM, X.CNT FROM (select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES_TABLE_SCAN ++/ INNER JOIN PUBLIC.BIB_HOLDINGS BH /++ PUBLIC.PRIMARY_KEY_1: ID = T.BH_ID ++/ WHERE (BH.SITE = 'WSTIAC') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= CAST(?1 AS BIGINT): CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT X.DIR_NUM, X.CNT FROM (select dir_num, count(*) as cnt from multi_pages t, b_holding bh where t.bh_id=bh.id and bh.site='Hello' group by dir_num) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES_TABLE_SCAN ++/ INNER JOIN PUBLIC.B_HOLDING BH /++ PUBLIC.PRIMARY_KEY_1: ID = T.BH_ID ++/ WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= CAST(?1 AS BIGINT): CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1
> rows (ordered): 1
select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh
where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num
select dir_num, count(*) as cnt from multi_pages t, b_holding bh
where t.bh_id=bh.id and bh.site='Hello' group by dir_num
having count(*) < 1000 order by dir_num asc;
> DIR_NUM CNT
> ------- ---
......@@ -55,7 +55,7 @@ having count(*) < 1000 order by dir_num asc;
> 3 1
> rows (ordered): 3
drop table multi_pages, bib_holdings;
drop table multi_pages, b_holding;
> ok
select * from dual where x = 1000000000000000000000;
......
......@@ -508,4 +508,4 @@ testview gaps birth vid weblog blojsom unsubscribe
imports bnot severity colon braces suppress star bxor band bor unary bsr puppy lor rcurly lcurly puppycrawl crawl ctor subclasses ell slist lnot land unchecked curly dtds question
forge chr trunc gabealbert tunebackup manifest
lumber thus taking repositories ago delegated mention leaks pgsql seeded felt efficiently mill mentioned forgot leaked restarted clearing occupies randomness warn implementing abstraction
spfile svr pkey synced
spfile svr pkey synced semicolon terminating
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论