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

--no commit message

--no commit message
上级 7e13d7de
...@@ -235,7 +235,7 @@ ...@@ -235,7 +235,7 @@
<javadoc <javadoc
sourcepath="src/main" sourcepath="src/main"
packagenames="org.h2.jdbc.*,org.h2.tools.*,org.h2.api.*,org.h2.store.*" 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"--> /> <!-- doclet="org.h2.tools.doclet.Doclet" docletpath="bin"-->
<copy todir="docs/javadoc"> <copy todir="docs/javadoc">
<fileset dir="src/docsrc/javadoc" includes="**/*"/> <fileset dir="src/docsrc/javadoc" includes="**/*"/>
......
...@@ -40,16 +40,19 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -40,16 +40,19 @@ 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>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>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) </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.
</li><li>REGEXP compatibility: So far String.matches was used, but for compatibility with MySQL, now Matcher.find is used. </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>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 </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>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><li>Compatibility: comparing columns with constants that are out of range does not throw an exception.
</li></ul> </li></ul>
...@@ -777,6 +780,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -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>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><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> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -529,7 +529,7 @@ H2 supports Lucene full text search and native full text search implementation. ...@@ -529,7 +529,7 @@ H2 supports Lucene full text search and native full text search implementation.
<h3>Using the Native Full Text Search</h3> <h3>Using the Native Full Text Search</h3>
<p> <p>
To initialize, call: To initialize, call:
<p> </p>
<pre> <pre>
CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init"; CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init";
CALL FT_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 { ...@@ -85,6 +85,7 @@ public abstract class Command implements CommandInterface {
public void checkCancelled() throws SQLException { public void checkCancelled() throws SQLException {
if (cancel) { if (cancel) {
cancel = false;
throw Message.getSQLException(ErrorCode.STATEMENT_WAS_CANCELLED); throw Message.getSQLException(ErrorCode.STATEMENT_WAS_CANCELLED);
} }
session.throttle(); session.throttle();
......
...@@ -9,6 +9,7 @@ import java.sql.SQLException; ...@@ -9,6 +9,7 @@ import java.sql.SQLException;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.log.LogSystem;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
...@@ -112,7 +113,9 @@ public class TransactionCommand extends Prepared { ...@@ -112,7 +113,9 @@ public class TransactionCommand extends Prepared {
s.close(); s.close();
} }
} }
db.getLog().checkpoint(); LogSystem log = db.getLog();
log.setDisabled(false);
log.checkpoint();
session.close(); session.close();
break; break;
} }
......
...@@ -306,7 +306,10 @@ public class ConnectionInfo { ...@@ -306,7 +306,10 @@ public class ConnectionInfo {
} }
public void setProperty(String key, String value) { 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() { public String getURL() {
......
...@@ -801,6 +801,9 @@ public class Database implements DataHandler { ...@@ -801,6 +801,9 @@ public class Database implements DataHandler {
} }
} }
} }
if (log != null) {
log.setDisabled(false);
}
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName); traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName);
if (eventListener != null) { if (eventListener != null) {
// allow the event listener to connect to the database // allow the event listener to connect to the database
......
...@@ -20,8 +20,10 @@ import java.sql.ResultSetMetaData; ...@@ -20,8 +20,10 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
...@@ -33,6 +35,9 @@ import java.util.Map.Entry; ...@@ -33,6 +35,9 @@ import java.util.Map.Entry;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
import org.h2.bnf.Bnf; import org.h2.bnf.Bnf;
import org.h2.constant.ErrorCode;
import org.h2.engine.Constants;
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.ObjectUtils;
...@@ -151,6 +156,10 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -151,6 +156,10 @@ class WebThread extends Thread implements DatabaseEventListener {
String hostname = socket.getInetAddress().getHostName(); String hostname = socket.getInetAddress().getHostName();
file = processRequest(file, hostname); file = processRequest(file, hostname);
if (file.length() == 0) {
// asynchronous request
return;
}
String message; String message;
byte[] bytes; byte[] bytes;
...@@ -184,22 +193,35 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -184,22 +193,35 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
message += "\n"; message += "\n";
server.trace(message); server.trace(message);
DataOutputStream output; DataOutputStream output = openOutput(message);
output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
output.write(message.getBytes());
if (bytes != null) { if (bytes != null) {
output.write(bytes); output.write(bytes);
} }
output.flush(); closeOutput(output);
output.close();
socket.close();
server.remove(this);
return; return;
} }
} catch (Exception e) { } catch (Exception e) {
TraceSystem.traceThrowable(e); TraceSystem.traceThrowable(e);
} }
} }
private DataOutputStream openOutput(String message) throws IOException {
DataOutputStream output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
output.write(message.getBytes());
return output;
}
private void closeOutput(DataOutputStream output) {
try {
output.flush();
output.close();
socket.close();
} catch (IOException e) {
// ignore
} finally {
server.remove(this);
}
}
protected String getComboBox(String[] elements, String selected) { protected String getComboBox(String[] elements, String selected) {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
...@@ -820,7 +842,7 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -820,7 +842,7 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
private String getLoginError(Exception e) { private String getLoginError(Exception e) {
if (e instanceof ClassNotFoundException) { if (e instanceof JdbcSQLException && ((JdbcSQLException) e).getErrorCode() == ErrorCode.CLASS_NOT_FOUND_1) {
return "${text.login.driverNotFound}<br />" + getStackTrace(0, e); return "${text.login.driverNotFound}<br />" + getStackTrace(0, e);
} else { } else {
return getStackTrace(0, e); return getStackTrace(0, e);
...@@ -828,27 +850,142 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -828,27 +850,142 @@ class WebThread extends Thread implements DatabaseEventListener {
} }
private String login() { private String login() {
String driver = attributes.getProperty("driver", ""); final String driver = attributes.getProperty("driver", "");
String url = attributes.getProperty("url", ""); final String url = attributes.getProperty("url", "");
String user = attributes.getProperty("user", ""); final String user = attributes.getProperty("user", "");
String password = attributes.getProperty("password", ""); final String password = attributes.getProperty("password", "");
session.put("autoCommit", "checked");
session.put("autoComplete", "1");
session.put("maxrows", "1000");
boolean thread = false;
if (socket != null
&& url.startsWith("jdbc:h2:")
&& !url.startsWith("jdbc:h2:tcp:")
&& !url.startsWith("jdbc:h2:ssl:")
&& !url.startsWith("jdbc:h2:mem:")) {
thread = true;
}
if (!thread) {
try {
Connection conn = server.getConnection(driver, url, user, password, this);
session.setConnection(conn);
session.put("url", url);
session.put("user", user);
session.remove("error");
settingSave();
return "frame.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e));
return "index.jsp";
}
}
class LoginTask implements Runnable, DatabaseEventListener {
private DataOutputStream output;
private PrintWriter writer;
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
LoginTask() throws IOException {
String message = "HTTP/1.1 200 OK\n";
message += "Content-Type: " + mimeType + "\n\n";
output = openOutput(message);
writer = new PrintWriter(output);
writer.println("<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"stylesheet.css\" /></head>");
writer.println("<body><h2>Opening Database</h2>URL: " + PageParser.escapeHtml(url) + "<br />");
writer.println("User: " + PageParser.escapeHtml(user) + "<br />");
writer.println("Version: " + Constants.getVersion() + "<br /><br />");
writer.flush();
log("Start...");
}
public void closingDatabase() {
log("Closing database");
}
public void diskSpaceIsLow(long stillAvailable) throws SQLException {
log("Disk space is low; still available: " + stillAvailable);
}
public void exceptionThrown(SQLException e, String sql) {
log("Exception: " + PageParser.escapeHtml(e.toString()) + " SQL: " + PageParser.escapeHtml(sql));
}
public void init(String url) {
log("Init: " + PageParser.escapeHtml(url));
}
public void opened() {
log("Database was opened");
}
public void setProgress(int state, String name, int x, int max) {
name = PageParser.escapeHtml(name);
if (state == listenerLastState) {
long time = System.currentTimeMillis();
if (listenerLastEvent + 500 < time) {
return;
}
listenerLastEvent = time;
} else {
listenerLastState = state;
}
switch(state) {
case DatabaseEventListener.STATE_BACKUP_FILE:
log("Backing up " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_CREATE_INDEX:
log("Creating index " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_RECOVER:
log("Recovering " + name + " " + (100L * x / max) + "%");
break;
case DatabaseEventListener.STATE_SCAN_FILE:
log("Scanning file " + name + " " + (100L * x / max) + "%");
break;
default:
log("Unknown state: " + state);
}
}
private synchronized void log(String message) {
if (output != null) {
message = dateFormat.format(new Date()) + ": " + message;
writer.println(message + "<br />");
writer.flush();
}
}
public void run() {
String sessionId = (String) session.get("sessionId");
try {
Connection conn = server.getConnection(driver, url, user, password, this);
session.setConnection(conn);
session.put("url", url);
session.put("user", user);
session.remove("error");
settingSave();
log("OK<script type=\"text/javascript\">top.location=\"frame.jsp?jsessionid=" +sessionId+ "\"</script></body></htm>");
// return "frame.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e));
log("Error<script type=\"text/javascript\">top.location=\"index.jsp?jsessionid=" +sessionId+ "\"</script></body></html>");
// return "index.jsp";
}
synchronized (this) {
closeOutput(output);
output = null;
}
}
}
try { try {
Connection conn = server.getConnection(driver, url, user, password, this); LoginTask login = new LoginTask();
session.setConnection(conn); Thread t = new Thread(login);
session.put("url", url); t.start();
session.put("user", user); } catch (IOException e) {
session.put("autoCommit", "checked"); // ignore
session.put("autoComplete", "1");
session.put("maxrows", "1000");
session.remove("error");
settingSave();
return "frame.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e));
return "index.jsp";
} }
return "";
} }
private String logout() { private String logout() {
try { try {
Connection conn = session.getConnection(); Connection conn = session.getConnection();
...@@ -1572,11 +1709,6 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1572,11 +1709,6 @@ class WebThread extends Thread implements DatabaseEventListener {
return session; return session;
} }
private void log(String s) {
int test;
System.out.println(s);
}
public void closingDatabase() { public void closingDatabase() {
log("Closing database"); log("Closing database");
} }
...@@ -1624,5 +1756,9 @@ class WebThread extends Thread implements DatabaseEventListener { ...@@ -1624,5 +1756,9 @@ class WebThread extends Thread implements DatabaseEventListener {
log("Unknown state: " + state); log("Unknown state: " + state);
} }
} }
private void log(String s) {
// System.out.println(s);
}
} }
...@@ -73,7 +73,22 @@ public class TableLink extends Table { ...@@ -73,7 +73,22 @@ public class TableLink extends Table {
int i = 0; int i = 0;
ObjectArray columnList = new ObjectArray(); ObjectArray columnList = new ObjectArray();
HashMap columnMap = new HashMap(); HashMap columnMap = new HashMap();
String catalog = null, schema = null;
while (rs.next()) { 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"); String n = rs.getString("COLUMN_NAME");
if (storesLowerCase && n.equals(StringUtils.toLowerEnglish(n))) { if (storesLowerCase && n.equals(StringUtils.toLowerEnglish(n))) {
n = StringUtils.toUpperEnglish(n); n = StringUtils.toUpperEnglish(n);
...@@ -87,6 +102,7 @@ public class TableLink extends Table { ...@@ -87,6 +102,7 @@ public class TableLink extends Table {
columnList.add(col); columnList.add(col);
columnMap.put(n, col); columnMap.put(n, col);
} }
// alternative solution
if (columnList.size() == 0) { if (columnList.size() == 0) {
Statement stat = null; Statement stat = null;
try { try {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.test; package org.h2.test;
import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Properties; import java.util.Properties;
...@@ -144,25 +145,36 @@ java org.h2.test.TestAll timer ...@@ -144,25 +145,36 @@ java org.h2.test.TestAll timer
/* /*
web page translation
set log 0; Thanks for the response. Yes I'm doing embedded so this is fine for
drop table test; me. One other question, I have noticed that once I cancel my
create table test(id int primary key, name varchar); PreparedStatement, it does not seem to work again. I couldn't find a
@LOOP 100000 insert into test values(?, space(1000)); way to clear it, so I guess I have to re-instantiate it?
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.
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 Delayed cancel: if you use the database in embedded mode, it depends on thread
corruption... 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 add MVCC
...@@ -254,9 +266,6 @@ translated .pdf ...@@ -254,9 +266,6 @@ translated .pdf
write tests using the PostgreSQL JDBC driver write tests using the PostgreSQL JDBC driver
support Oracle functions:
TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER;
*/ */
// run TestHalt // run TestHalt
...@@ -561,7 +570,7 @@ TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER; ...@@ -561,7 +570,7 @@ TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER;
// jdbc // jdbc
new TestCancel().runTest(this); new TestCancel().runTest(this);
// new TestDatabaseEventListener().runTest(this); new TestDatabaseEventListener().runTest(this);
new TestDataSource().runTest(this); new TestDataSource().runTest(this);
new TestManyJdbcObjects().runTest(this); new TestManyJdbcObjects().runTest(this);
new TestMetaData().runTest(this); new TestMetaData().runTest(this);
......
...@@ -22,6 +22,30 @@ public class TestLinkedTable extends TestBase { ...@@ -22,6 +22,30 @@ public class TestLinkedTable extends TestBase {
testLinkSchema(); testLinkSchema();
testLinkEmitUpdates(); testLinkEmitUpdates();
testLinkTable(); 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 { private void testLinkDrop() throws Exception {
......
...@@ -7,6 +7,7 @@ package org.h2.test.jdbc; ...@@ -7,6 +7,7 @@ package org.h2.test.jdbc;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import org.h2.api.DatabaseEventListener; import org.h2.api.DatabaseEventListener;
...@@ -14,9 +15,45 @@ import org.h2.test.TestBase; ...@@ -14,9 +15,45 @@ import org.h2.test.TestBase;
public class TestDatabaseEventListener extends TestBase implements DatabaseEventListener { public class TestDatabaseEventListener extends TestBase implements DatabaseEventListener {
private boolean calledOpened, calledClosingDatabase; private boolean calledOpened, calledClosingDatabase, calledScan;
public void test() throws Exception { 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(); Properties p = new Properties();
p.setProperty("user", "sa"); p.setProperty("user", "sa");
p.setProperty("password", "sa"); p.setProperty("password", "sa");
...@@ -47,6 +84,9 @@ public class TestDatabaseEventListener extends TestBase implements DatabaseEvent ...@@ -47,6 +84,9 @@ public class TestDatabaseEventListener extends TestBase implements DatabaseEvent
} }
public void setProgress(int state, String name, int x, int max) { 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 { ...@@ -28,6 +28,7 @@ public class TestPreparedStatement extends TestBase {
deleteDb("preparedStatement"); deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement"); Connection conn = getConnection("preparedStatement");
testCancelReuse(conn);
testCoalesce(conn); testCoalesce(conn);
testPreparedStatementMetaData(conn); testPreparedStatementMetaData(conn);
testDate(conn); testDate(conn);
...@@ -49,6 +50,33 @@ public class TestPreparedStatement extends TestBase { ...@@ -49,6 +50,33 @@ public class TestPreparedStatement extends TestBase {
conn.close(); 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 { private void testCoalesce(Connection conn) throws Exception {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.executeUpdate("create table test(tm timestamp)"); stat.executeUpdate("create table test(tm timestamp)");
......
...@@ -21,14 +21,14 @@ create table multi_pages(dir_num int, bh_id int); ...@@ -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); insert into multi_pages values(1, 1), (2, 2), (3, 3);
> update count: 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 > 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 > update count: 3
select * from (select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh select * from (select dir_num, count(*) as cnt from multi_pages t, b_holding bh
where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num) as x where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc; where cnt < 1000 order by dir_num asc;
> DIR_NUM CNT > DIR_NUM CNT
> ------- --- > ------- ---
...@@ -37,16 +37,16 @@ where cnt < 1000 order by dir_num asc; ...@@ -37,16 +37,16 @@ where cnt < 1000 order by dir_num asc;
> 3 1 > 3 1
> rows (ordered): 3 > rows (ordered): 3
explain select * from (select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh 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='WSTIAC' group by dir_num) as x where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc; where cnt < 1000 order by dir_num asc;
> PLAN > 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 > rows (ordered): 1
select dir_num, count(*) as cnt from multi_pages t, bib_holdings bh select dir_num, count(*) as cnt from multi_pages t, b_holding bh
where t.bh_id=bh.id and bh.site='WSTIAC' group by dir_num where t.bh_id=bh.id and bh.site='Hello' group by dir_num
having count(*) < 1000 order by dir_num asc; having count(*) < 1000 order by dir_num asc;
> DIR_NUM CNT > DIR_NUM CNT
> ------- --- > ------- ---
...@@ -55,7 +55,7 @@ having count(*) < 1000 order by dir_num asc; ...@@ -55,7 +55,7 @@ having count(*) < 1000 order by dir_num asc;
> 3 1 > 3 1
> rows (ordered): 3 > rows (ordered): 3
drop table multi_pages, bib_holdings; drop table multi_pages, b_holding;
> ok > ok
select * from dual where x = 1000000000000000000000; select * from dual where x = 1000000000000000000000;
......
...@@ -508,4 +508,4 @@ testview gaps birth vid weblog blojsom unsubscribe ...@@ -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 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 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 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论