提交 68882ef5 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 2bc107ec
#Tue Mar 18 08:37:19 CET 2008 #Thu Mar 20 17:07:30 CET 2008
benchmark.drivers.dir=C\:/data/java benchmark.drivers.dir=C\:/data/java
javac=javac javac=javac
jdk=1.4 jdk=1.4
......
...@@ -52,29 +52,29 @@ ...@@ -52,29 +52,29 @@
</target> </target>
<target name="codeswitchPrepare" depends="clean"> <target name="codeswitchPrepare" depends="clean">
<javac executable="${javac}" srcdir="src/tools" destdir="bin" debug="true" includes="org/h2/tools/code/CodeSwitch.java"/> <javac executable="${javac}" srcdir="src/tools" destdir="bin" debug="true" includes="org/h2/build/code/CodeSwitch.java"/>
</target> </target>
<target name="codeswitchAndroid" depends="codeswitchPrepare"> <target name="codeswitchAndroid" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin"> <java classname="org.h2.build.code.CodeSwitch" classpath="bin">
<arg line="+JDK13 -JDK14 -JDK16 -AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/> <arg line="+JDK13 -JDK14 -JDK16 -AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/>
</java> </java>
</target> </target>
<target name="codeswitchJdk13" depends="codeswitchPrepare"> <target name="codeswitchJdk13" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin"> <java classname="org.h2.build.code.CodeSwitch" classpath="bin">
<arg line="+JDK13 -JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/> <arg line="+JDK13 -JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.3"/>
</java> </java>
</target> </target>
<target name="codeswitchJdk14" depends="codeswitchPrepare"> <target name="codeswitchJdk14" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin"> <java classname="org.h2.build.code.CodeSwitch" classpath="bin">
<arg line="-JDK13 +JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.4"/> <arg line="-JDK13 +JDK14 -JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.4"/>
</java> </java>
</target> </target>
<target name="codeswitchJdk16" depends="codeswitchPrepare"> <target name="codeswitchJdk16" depends="codeswitchPrepare">
<java classname="org.h2.tools.code.CodeSwitch" classpath="bin"> <java classname="org.h2.build.code.CodeSwitch" classpath="bin">
<arg line="-JDK13 +JDK14 +JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.6"/> <arg line="-JDK13 +JDK14 +JDK16 +AWT src/main/org/h2 -set ant-build.properties jdk 1.6"/>
</java> </java>
</target> </target>
...@@ -163,16 +163,16 @@ ...@@ -163,16 +163,16 @@
<copy todir="docs"> <copy todir="docs">
<fileset dir="src/docsrc" includes="index.html"/> <fileset dir="src/docsrc" includes="index.html"/>
</copy> </copy>
<java classname="org.h2.tools.code.CheckJavadoc" classpath="bin"/> <java classname="org.h2.build.code.CheckJavadoc" classpath="bin"/>
<java classname="org.h2.tools.code.CheckTextFiles" classpath="bin"/> <java classname="org.h2.build.code.CheckTextFiles" classpath="bin"/>
<java classname="org.h2.tools.doc.GenerateDoc" classpath="bin"/> <java classname="org.h2.build.doc.GenerateDoc" classpath="bin"/>
<java classname="org.h2.tools.i18n.PrepareTranslation" classpath="bin"/> <java classname="org.h2.build.i18n.PrepareTranslation" classpath="bin"/>
<java classname="org.h2.tools.indexer.Indexer" classpath="bin"/> <java classname="org.h2.build.indexer.Indexer" classpath="bin"/>
<java classname="org.h2.tools.doc.MergeDocs" classpath="bin"/> <java classname="org.h2.build.doc.MergeDocs" classpath="bin"/>
<java classname="org.h2.tools.doc.WebSite" classpath="bin"/> <java classname="org.h2.build.doc.WebSite" classpath="bin"/>
<java classname="org.h2.tools.doc.LinkChecker" classpath="bin"/> <java classname="org.h2.build.doc.LinkChecker" classpath="bin"/>
<java classname="org.h2.tools.doc.XMLChecker" classpath="bin"/> <java classname="org.h2.build.doc.XMLChecker" classpath="bin"/>
<java classname="org.h2.tools.doc.SpellChecker" classpath="bin"/> <java classname="org.h2.build.doc.SpellChecker" classpath="bin"/>
</target> </target>
<target name="init"> <target name="init">
...@@ -200,12 +200,10 @@ ...@@ -200,12 +200,10 @@
</manifest> </manifest>
<jar jarfile="bin/h2.jar" basedir="bin" manifest="bin/META-INF/MANIFEST.MF"> <jar jarfile="bin/h2.jar" basedir="bin" manifest="bin/META-INF/MANIFEST.MF">
<include name="**/*.*"/> <include name="**/*.*"/>
<exclude name="org/h2/tools/code/**/*.*"/> <exclude name="org/h2/build/**/*.*"/>
<exclude name="org/h2/tools/doc/**/*.*"/> <exclude name="org/h2/dev/**/*.*"/>
<exclude name="org/h2/tools/doclet/**/*.*"/>
<exclude name="org/h2/tools/indexer/**/*.*"/>
<exclude name="org/h2/test/**/*.*"/>
<exclude name="org/h2/samples/**/*.*"/> <exclude name="org/h2/samples/**/*.*"/>
<exclude name="org/h2/test/**/*.*"/>
<exclude name="**/*.bat"/> <exclude name="**/*.bat"/>
<exclude name="**/*.txt"/> <exclude name="**/*.txt"/>
</jar> </jar>
...@@ -239,12 +237,12 @@ ...@@ -239,12 +237,12 @@
<target name="javadoc"> <target name="javadoc">
<javac executable="${javac}" srcdir="src/main" destdir="bin" debug="true" includes="org/h2/util/StringUtils.java"/> <javac executable="${javac}" srcdir="src/main" destdir="bin" debug="true" includes="org/h2/util/StringUtils.java"/>
<javac executable="${javac}" srcdir="src/test" destdir="bin" debug="true" includes="org/h2/test/bnf/*.java"/> <javac executable="${javac}" srcdir="src/test" destdir="bin" debug="true" includes="org/h2/test/bnf/*.java"/>
<javac executable="${javac}" srcdir="src/tools" destdir="bin" debug="true" includes="org/h2/tools/doclet/*.java"/> <javac executable="${javac}" srcdir="src/tools" destdir="bin" debug="true" includes="org/h2/build/doclet/*.java"/>
<mkdir dir="docs/javadoc"/> <mkdir dir="docs/javadoc"/>
<javadoc <javadoc
sourcepath="src/main" sourcepath="src/main"
packagenames="org.h2.jdbc.*,org.h2.jdbcx.*,org.h2.tools.*,org.h2.api.*,org.h2.constant.*" packagenames="org.h2.jdbc.*,org.h2.jdbcx.*,org.h2.tools.*,org.h2.api.*,org.h2.constant.*"
doclet="org.h2.tools.doclet.Doclet" doclet="org.h2.build.doclet.Doclet"
docletpath="bin" docletpath="bin"
/> />
<copy todir="docs/javadoc"> <copy todir="docs/javadoc">
...@@ -258,7 +256,7 @@ ...@@ -258,7 +256,7 @@
sourcepath="src/main;src/test;src/tools" sourcepath="src/main;src/test;src/tools"
classpath="${path.lucene.jar};${path.servlet.jar};${java.class.path}" classpath="${path.lucene.jar};${path.servlet.jar};${java.class.path}"
packagenames="org.h2.*" packagenames="org.h2.*"
doclet="org.h2.tools.doclet.Doclet" doclet="org.h2.build.doclet.Doclet"
docletpath="bin" docletpath="bin"
additionalparam="-J-Dh2.interfacesOnly=false -J-Dh2.destDir=docs/javadocImpl" additionalparam="-J-Dh2.interfacesOnly=false -J-Dh2.destDir=docs/javadocImpl"
/> />
...@@ -266,7 +264,7 @@ ...@@ -266,7 +264,7 @@
sourcepath="src/main;src/test;src/tools" sourcepath="src/main;src/test;src/tools"
noindex="true" noindex="true"
packagenames="org.h2.*" packagenames="org.h2.*"
excludepackagenames="org.h2.tools.doclet" excludepackagenames="org.h2.build.*,org.h2.dev.*"
classpath="${path.lucene.jar};${path.servlet.jar};${java.class.path}" classpath="${path.lucene.jar};${path.servlet.jar};${java.class.path}"
destDir="docs/javadocImpl" destDir="docs/javadocImpl"
/> />
......
...@@ -32,6 +32,8 @@ Advanced Topics ...@@ -32,6 +32,8 @@ Advanced Topics
Run as Windows Service</a><br /> Run as Windows Service</a><br />
<a href="#odbc_driver"> <a href="#odbc_driver">
ODBC Driver</a><br /> ODBC Driver</a><br />
<a href="#microsoft_dot_net">
Using H2 in Microsoft .NET</a><br />
<a href="#acid"> <a href="#acid">
ACID</a><br /> ACID</a><br />
<a href="#durability_problems"> <a href="#durability_problems">
...@@ -474,6 +476,29 @@ Also, it is currently not possible to use encrypted SSL connections. ...@@ -474,6 +476,29 @@ Also, it is currently not possible to use encrypted SSL connections.
Therefore the ODBC driver should not be used where security is important. Therefore the ODBC driver should not be used where security is important.
</p> </p>
<br /><a name="microsoft_dot_net"></a>
<h2>Using H2 in Microsoft .NET</h2>
<p>
The database can be used from Microsoft .NET even without using Java, by using IKVM.NET:
</p>
<ul><li>Install the .NET Framework from <a href="http://www.microsoft.com">Microsoft</a>.
Mono has not yet been tested.
</li><li>Install <a href="http://www.ikvm.net">IKVM.NET</a>.
</li><li>Copy the h2.jar file to ikvm/bin
</li><li>Run the H2 Console using:
<code>ikvm -jar h2.jar</code>
</li><li>Convert the H2 Console to an .exe file using:
<code>ikvmc -target:winexe h2.jar</code>.
You may ignore the warnings.
</li><li>Create a .dll file using (change the version accordingly):
<code>ikvmc.exe -target:library -version:1.0.68.0 h2.jar</code>
</li></ul>
<p>
If you want your C# application use H2, you need to add the h2.dll and the
IKVM.OpenJDK.ClassLibrary.dll to your C# solution. See also the short
<a href="http://groups.google.com/group/h2-database/browse_thread/thread/400bc5a9bc9de3fd">C# source code example</a>.
</p>
<br /><a name="acid"></a> <br /><a name="acid"></a>
<h2>ACID</h2> <h2>ACID</h2>
<p> <p>
......
...@@ -230,6 +230,11 @@ Orion</a><br /> ...@@ -230,6 +230,11 @@ Orion</a><br />
J2EE Application Server. J2EE Application Server.
</p> </p>
<p><a href="http://www.phase-6.de">
Phase-6</a><br />
A computer based learning software.
</p>
<p><a href="http://www.polepos.org"> <p><a href="http://www.polepos.org">
PolePosition</a><br /> PolePosition</a><br />
Open source database benchmark. Open source database benchmark.
......
...@@ -18,7 +18,7 @@ Welcome to H2, the free SQL database engine. ...@@ -18,7 +18,7 @@ Welcome to H2, the free SQL database engine.
<br /> <br />
<p> <p>
<a href="quickstartText.html" style="font-size: 16px; font-weight: bold">Quickstart</a> <a href="quickstart.html" style="font-size: 16px; font-weight: bold">Quickstart</a>
<br /> <br />
Click here to get a fast overview. Click here to get a fast overview.
</p> </p>
......
...@@ -52,7 +52,7 @@ Initial Developer: H2 Group ...@@ -52,7 +52,7 @@ Initial Developer: H2 Group
<div class="menu"> <div class="menu">
<b><a href="main.html" target="main">Home</a></b><br /> <b><a href="main.html" target="main">Home</a></b><br />
<a href="quickstartText.html" target="main">Quickstart</a><br /> <a href="quickstart.html" target="main">Quickstart</a><br />
<a href="installation.html" target="main">Installation</a><br /> <a href="installation.html" target="main">Installation</a><br />
<a href="tutorial.html" target="main">Tutorial</a><br /> <a href="tutorial.html" target="main">Tutorial</a><br />
<a href="features.html" target="main">Features</a><br /> <a href="features.html" target="main">Features</a><br />
......
...@@ -28,6 +28,8 @@ Tutorial ...@@ -28,6 +28,8 @@ Tutorial
CSV (Comma Separated Values) Support</a><br /> CSV (Comma Separated Values) Support</a><br />
<a href="#upgrade_backup_restore"> <a href="#upgrade_backup_restore">
Upgrade, Backup, and Restore</a><br /> Upgrade, Backup, and Restore</a><br />
<a href="#command_line_tools">
Command Line Tools</a><br />
<a href="#open_office"> <a href="#open_office">
Using OpenOffice Base</a><br /> Using OpenOffice Base</a><br />
<a href="#web_start"> <a href="#web_start">
...@@ -492,6 +494,36 @@ The Backup tool (org.h2.tools.Backup) can not be used to create a online backup; ...@@ -492,6 +494,36 @@ The Backup tool (org.h2.tools.Backup) can not be used to create a online backup;
the database must not be in use while running this program. the database must not be in use while running this program.
</p> </p>
<br /><a name="command_line_tools"></a>
<h2>Command Line Tools</h2>
<p>
This database comes with a number of command line tools. To get more information about a tool,
start it with the parameter '-?', for example:
</p>
<pre>
java -cp h2.jar org.h2.tools.Backup -?
</pre>
<p>
The command line tools are:
</p>
<ul><li><b>Backup</b> creates a backup of a database.
</li><li><b>ChangePassword</b> allows to change the file password of a database.
</li><li><b>Console</b> starts the browser based H2 Console.
</li><li><b>ConvertTraceFile</b> converts a .trace.db file to a Java application and SQL script.
</li><li><b>CreateCluster</b> creates a cluster from a standalone database.
</li><li><b>DeleteDbFiles</b> deletes all files belonging to a database.
</li><li><b>Script</b> allows to convert a database to a SQL script for backup or migration.
</li><li><b>Recover</b> helps recovering a corrupted database.
</li><li><b>Restore</b> restores a backup of a database.
</li><li><b>RunScript</b> runs a SQL script against a database.
</li><li><b>Server</b> is used in the server mode to start a H2 server.
</li><li><b>Shell</b> is a command line database tool.
</li></ul>
<p>
The tools can also be called from an application by calling the main or another public methods.
For details, see the Javadoc documentation.
</p>
<br /><a name="open_office"></a> <br /><a name="open_office"></a>
<h2>Using OpenOffice Base</h2> <h2>Using OpenOffice Base</h2>
<p> <p>
...@@ -557,11 +589,28 @@ Example permission tags: ...@@ -557,11 +589,28 @@ Example permission tags:
For many databases, opening a connection is slow, and it is a good idea to use a connection pool For many databases, opening a connection is slow, and it is a good idea to use a connection pool
to re-use connections. For H2 however opening a connection usually is fast if the database is already to re-use connections. For H2 however opening a connection usually is fast if the database is already
open. Using a connection pool manager for H2 actually slows down the process a bit, except if open. Using a connection pool manager for H2 actually slows down the process a bit, except if
file encryption is used (in this case opening a connection is about half as fast are using file encryption is used (in this case opening a connection is about half as fast as using
a connection pool). A simple connection pool is: a connection pool). A simple connection pool manager is included in H2. It is based on the
<a href="http://www.source-code.biz/snippets/java/8.htm">Mini Connection Pool Manager</a>. <a href="http://www.source-code.biz/snippets/java/8.htm">Mini Connection Pool Manager</a>
There are other, more complex connection pools available, for example from Christian d'Heureuse. There are other, more complex connection pools available, for example
<a href="http://jakarta.apache.org/commons/dbcp/">DBCP</a>. <a href="http://jakarta.apache.org/commons/dbcp/">DBCP</a>. The build-in
connection pool manager is used as follows:
<pre>
// init
JdbcDataSource ds = new JdbcDataSource();
ds.setURL("jdbc:h2:~/test");
ds.setUser("sa");
ds.setPassword("sa");
JdbcConnectionPoolManager man = new JdbcConnectionPoolManager(ds);
// use
Connection conn = man.getConnection();
...
conn.close();
// dispose
man.dispose();
</pre>
</p> </p>
<br /><a name="fulltext"></a> <br /><a name="fulltext"></a>
......
...@@ -37,6 +37,7 @@ org.h2.jdbc<br /> ...@@ -37,6 +37,7 @@ org.h2.jdbc<br />
<a href="org/h2/jdbc/JdbcSQLException.html" target="javadoc">SQLException</a><br /> <a href="org/h2/jdbc/JdbcSQLException.html" target="javadoc">SQLException</a><br />
<a href="org/h2/jdbc/JdbcStatement.html" target="javadoc">Statement</a><br /> <a href="org/h2/jdbc/JdbcStatement.html" target="javadoc">Statement</a><br />
org.h2.jdbcx<br /> org.h2.jdbcx<br />
<a href="org/h2/jdbcx/JdbcConnectionPoolManager.html" target="javadoc">ConnectionPoolManager</a><br />
<a href="org/h2/jdbcx/JdbcDataSource.html" target="javadoc">DataSource</a><br /> <a href="org/h2/jdbcx/JdbcDataSource.html" target="javadoc">DataSource</a><br />
<a href="org/h2/jdbcx/JdbcDataSourceFactory.html" target="javadoc">DataSourceFactory</a><br /> <a href="org/h2/jdbcx/JdbcDataSourceFactory.html" target="javadoc">DataSourceFactory</a><br />
<a href="org/h2/jdbcx/JdbcXAConnection.html" target="javadoc">XAConnection</a><br /> <a href="org/h2/jdbcx/JdbcXAConnection.html" target="javadoc">XAConnection</a><br />
...@@ -59,6 +60,7 @@ org.h2.tools<br /> ...@@ -59,6 +60,7 @@ org.h2.tools<br />
<a href="org/h2/tools/Restore.html" target="javadoc">Restore</a><br /> <a href="org/h2/tools/Restore.html" target="javadoc">Restore</a><br />
<a href="org/h2/tools/RunScript.html" target="javadoc">RunScript</a><br /> <a href="org/h2/tools/RunScript.html" target="javadoc">RunScript</a><br />
<a href="org/h2/tools/Server.html" target="javadoc">Server</a><br /> <a href="org/h2/tools/Server.html" target="javadoc">Server</a><br />
<a href="org/h2/tools/Shell.html" target="javadoc">Shell</a><br />
<a href="org/h2/tools/SimpleResultSet.html" target="javadoc">SimpleResultSet</a><br /> <a href="org/h2/tools/SimpleResultSet.html" target="javadoc">SimpleResultSet</a><br />
<a href="org/h2/tools/SimpleRowSource.html" target="javadoc">SimpleRowSource</a><br /> <a href="org/h2/tools/SimpleRowSource.html" target="javadoc">SimpleRowSource</a><br />
<br /> <br />
......
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.
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: Christian d'Heureuse, www.source-code.biz
*
* This class is dual-licensed LGPL and under the H2 License.
*
* This module is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version. See http://www.gnu.org/licenses/lgpl.html.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
package org.h2.jdbcx;
import java.util.Stack;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.PooledConnection;
/**
* A simple standalone JDBC connection pool manager.
* It is based on the
* <a href="http://www.source-code.biz/snippets/java/8.htm">
* MiniConnectionPoolManager written by Christian d'Heureuse (JDK 1.5)
* </a>.
*
* @author Christian d'Heureuse (<a href="http://www.source-code.biz">www.source-code.biz</a>)
* @author Thomas Mueller (ported to JDK 1.4)
*/
public class JdbcConnectionPoolManager {
private ConnectionPoolDataSource dataSource;
private int maxConnections;
private int timeout;
private PrintWriter logWriter;
private Stack recycledConnections;
private int activeConnections;
private PoolConnectionEventListener poolConnectionEventListener;
private boolean isDisposed;
/**
* This inThrown in {@link #getConnection()} when no free connection becomes
* available within <code>timeout</code> seconds.
*/
public static class TimeoutException extends RuntimeException {
private static final long serialVersionUID = 1;
public TimeoutException() {
super("Timeout while waiting for a free database connection.");
}
}
/**
* Constructs a JdbcConnectionPoolManager object with a timeout of 60
* seconds.
*
* @param dataSource the data source for the connections.
* @param maxConnections the maximum number of connections.
*/
public JdbcConnectionPoolManager(ConnectionPoolDataSource dataSource, int maxConnections) {
this(dataSource, maxConnections, 60);
}
/**
* Constructs a JdbcConnectionPoolManager object.
*
* @param dataSource the data source for the connections.
* @param maxConnections the maximum number of connections.
* @param timeout the maximum time in seconds to wait for a free connection.
*/
public JdbcConnectionPoolManager(ConnectionPoolDataSource dataSource, int maxConnections, int timeout) {
this.dataSource = dataSource;
this.maxConnections = maxConnections;
this.timeout = timeout;
try {
logWriter = dataSource.getLogWriter();
} catch (SQLException e) {
}
if (maxConnections < 1) {
throw new IllegalArgumentException("Invalid maxConnections value.");
}
recycledConnections = new Stack();
poolConnectionEventListener = new PoolConnectionEventListener();
}
/**
* Closes all unused pooled connections.
*/
public synchronized void dispose() throws SQLException {
if (isDisposed) {
return;
}
isDisposed = true;
SQLException e = null;
while (!recycledConnections.isEmpty()) {
PooledConnection pc = (PooledConnection) recycledConnections.pop();
try {
pc.close();
} catch (SQLException e2) {
if (e == null) {
e = e2;
}
}
}
if (e != null) {
throw e;
}
}
/**
* Retrieves a connection from the connection pool. If
* <code>maxConnections</code> connections are already in use, the method
* waits until a connection becomes available or <code>timeout</code>
* seconds elapsed. When the application is finished using the connection,
* it must close it in order to return it to the pool.
*
* @return a new Connection object.
* @throws TimeoutException when no connection becomes available within
* <code>timeout</code> seconds.
*/
public Connection getConnection() throws SQLException {
for (int i = 0;; i++) {
synchronized (this) {
if (activeConnections < maxConnections) {
return getConnectionNow();
}
if (i >= timeout) {
throw new TimeoutException();
}
try {
wait(1000);
} catch (InterruptedException e) {
// ignore
}
}
}
}
private Connection getConnectionNow() throws SQLException {
if (isDisposed) {
throw new IllegalStateException("Connection pool has been disposed.");
}
PooledConnection pc;
if (!recycledConnections.empty()) {
pc = (PooledConnection) recycledConnections.pop();
} else {
pc = dataSource.getPooledConnection();
}
Connection conn = pc.getConnection();
activeConnections++;
pc.addConnectionEventListener(poolConnectionEventListener);
assertInnerState();
return conn;
}
private synchronized void recycleConnection(PooledConnection pc) {
if (isDisposed) {
disposeConnection(pc);
return;
}
if (activeConnections <= 0) {
throw new AssertionError();
}
activeConnections--;
notifyAll();
recycledConnections.push(pc);
assertInnerState();
}
private synchronized void disposeConnection(PooledConnection pc) {
if (activeConnections <= 0) {
throw new AssertionError();
}
activeConnections--;
notifyAll();
try {
pc.close();
} catch (SQLException e) {
log("Error while closing database connection: " + e.toString());
}
assertInnerState();
}
private void log(String msg) {
String s = "JdbcConnectionPoolManager: " + msg;
try {
if (logWriter == null) {
System.err.println(s);
} else {
logWriter.println(s);
}
} catch (Exception e) {
}
}
private void assertInnerState() {
if (activeConnections < 0) {
throw new AssertionError();
}
if (activeConnections + recycledConnections.size() > maxConnections) {
throw new AssertionError();
}
}
private class PoolConnectionEventListener implements ConnectionEventListener {
public void connectionClosed(ConnectionEvent event) {
PooledConnection pc = (PooledConnection) event.getSource();
pc.removeConnectionEventListener(this);
recycleConnection(pc);
}
public void connectionErrorOccurred(ConnectionEvent event) {
PooledConnection pc = (PooledConnection) event.getSource();
pc.removeConnectionEventListener(this);
disposeConnection(pc);
}
}
/**
* Returns the number of active (open) connections of this pool. This is the
* number of <code>Connection</code> objects that have been issued by
* getConnection() for which <code>Connection.close()</code> has
* not yet been called.
*
* @return the number of active connections.
*/
public synchronized int getActiveConnections() {
return activeConnections;
}
}
...@@ -13,13 +13,13 @@ import org.h2.util.StringUtils; ...@@ -13,13 +13,13 @@ import org.h2.util.StringUtils;
* This class is used by the H2 Console. * This class is used by the H2 Console.
*/ */
public class ConnectionInfo { public class ConnectionInfo {
String name, driver, url, user; public String name, driver, url, user;
int lastAccess; int lastAccess;
ConnectionInfo() { ConnectionInfo() {
} }
ConnectionInfo(String data) { public ConnectionInfo(String data) {
String[] array = StringUtils.arraySplit(data, '|', false); String[] array = StringUtils.arraySplit(data, '|', false);
name = get(array, 0); name = get(array, 0);
driver = get(array, 1); driver = get(array, 1);
......
...@@ -70,12 +70,12 @@ public class WebServer implements Service { ...@@ -70,12 +70,12 @@ public class WebServer implements Service {
"Generic JNDI Data Source|javax.naming.InitialContext|java:comp/env/jdbc/Test|sa", "Generic JNDI Data Source|javax.naming.InitialContext|java:comp/env/jdbc/Test|sa",
"Generic Firebird Server|org.firebirdsql.jdbc.FBDriver|jdbc:firebirdsql:localhost:c:/temp/firebird/test|sysdba", "Generic Firebird Server|org.firebirdsql.jdbc.FBDriver|jdbc:firebirdsql:localhost:c:/temp/firebird/test|sysdba",
"Generic OneDollarDB|in.co.daffodil.db.jdbc.DaffodilDBDriver|jdbc:daffodilDB_embedded:school;path=C:/temp;create=true|sa", "Generic OneDollarDB|in.co.daffodil.db.jdbc.DaffodilDBDriver|jdbc:daffodilDB_embedded:school;path=C:/temp;create=true|sa",
"Generic DB2|COM.ibm.db2.jdbc.net.DB2Driver|jdbc:db2://<host>/<db>|" , "Generic DB2|COM.ibm.db2.jdbc.net.DB2Driver|jdbc:db2://localhost/test|" ,
"Generic Oracle|oracle.jdbc.driver.OracleDriver|jdbc:oracle:thin:@<host>:1521:<instance>|scott" , "Generic Oracle|oracle.jdbc.driver.OracleDriver|jdbc:oracle:thin:@localhost:1521:test|scott" ,
"Generic MS SQL Server 2000|com.microsoft.jdbc.sqlserver.SQLServerDriver|jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sqlexpress|sa", "Generic MS SQL Server 2000|com.microsoft.jdbc.sqlserver.SQLServerDriver|jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sqlexpress|sa",
"Generic MS SQL Server 2005|com.microsoft.sqlserver.jdbc.SQLServerDriver|jdbc:sqlserver://localhost;DatabaseName=test|sa", "Generic MS SQL Server 2005|com.microsoft.sqlserver.jdbc.SQLServerDriver|jdbc:sqlserver://localhost;DatabaseName=test|sa",
"Generic PostgreSQL|org.postgresql.Driver|jdbc:postgresql:<db>|" , "Generic PostgreSQL|org.postgresql.Driver|jdbc:postgresql:test|" ,
"Generic MySQL|com.mysql.jdbc.Driver|jdbc:mysql://<host>:<port>/<db>|" , "Generic MySQL|com.mysql.jdbc.Driver|jdbc:mysql://localhost:3306/test|" ,
"Generic HSQLDB|org.hsqldb.jdbcDriver|jdbc:hsqldb:test;hsqldb.default_table_type=cached|sa" , "Generic HSQLDB|org.hsqldb.jdbcDriver|jdbc:hsqldb:test;hsqldb.default_table_type=cached|sa" ,
"Generic Derby (Server)|org.apache.derby.jdbc.ClientDriver|jdbc:derby://localhost:1527/test;create=true|sa", "Generic Derby (Server)|org.apache.derby.jdbc.ClientDriver|jdbc:derby://localhost:1527/test;create=true|sa",
"Generic Derby (Embedded)|org.apache.derby.jdbc.EmbeddedDriver|jdbc:derby:test;create=true|sa", "Generic Derby (Embedded)|org.apache.derby.jdbc.EmbeddedDriver|jdbc:derby:test;create=true|sa",
......
...@@ -833,8 +833,10 @@ public class Recover implements DataHandler { ...@@ -833,8 +833,10 @@ public class Recover implements DataHandler {
Map.Entry entry = (Entry) it.next(); Map.Entry entry = (Entry) it.next();
Integer objectId = (Integer) entry.getKey(); Integer objectId = (Integer) entry.getKey();
String name = (String) entry.getValue(); String name = (String) entry.getValue();
if (objectIdSet.contains(objectId)) {
writer.println("INSERT INTO " + name + " SELECT * FROM O_" + objectId + ";"); writer.println("INSERT INTO " + name + " SELECT * FROM O_" + objectId + ";");
} }
}
for (Iterator it = objectIdSet.iterator(); it.hasNext();) { for (Iterator it = objectIdSet.iterator(); it.hasNext();) {
Integer objectId = (Integer) it.next(); Integer objectId = (Integer) it.next();
writer.println("DROP TABLE O_" + objectId + ";"); writer.println("DROP TABLE O_" + objectId + ";");
......
...@@ -47,8 +47,8 @@ public class RunScript { ...@@ -47,8 +47,8 @@ public class RunScript {
* <li>-user username </li> * <li>-user username </li>
* <li>-password password </li> * <li>-password password </li>
* <li>-script filename (default file name is backup.sql) </li> * <li>-script filename (default file name is backup.sql) </li>
* <li>-driver driver the JDBC driver class name (not required for H2) * <li>-driver driver the JDBC driver class name (not required for most
* </li> * databases) </li>
* <li>-options to specify a list of options (only for H2 and only when * <li>-options to specify a list of options (only for H2 and only when
* using the embedded mode) </li> * using the embedded mode) </li>
* </ul> * </ul>
...@@ -120,16 +120,13 @@ public class RunScript { ...@@ -120,16 +120,13 @@ public class RunScript {
return; return;
} }
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
// for(int i=0; i<10; i++) {
// int test;
if (options != null) { if (options != null) {
executeRunscript(url, user, password, script, options); executeRunscript(url, user, password, script, options);
} else { } else {
execute(url, user, password, script, null, continueOnError); execute(url, user, password, script, null, continueOnError);
} }
// }
time = System.currentTimeMillis() - time;
if (showTime) { if (showTime) {
time = System.currentTimeMillis() - time;
System.out.println("Done in " + time + " ms"); System.out.println("Done in " + time + " ms");
} }
} }
......
...@@ -8,15 +8,22 @@ package org.h2.tools; ...@@ -8,15 +8,22 @@ package org.h2.tools;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.PrintStream;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.StringTokenizer; import java.util.Properties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.message.Message; import org.h2.message.Message;
import org.h2.server.web.ConnectionInfo;
import org.h2.util.ClassUtils; import org.h2.util.ClassUtils;
import org.h2.util.FileUtils;
import org.h2.util.JdbcDriverUtils;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
/** /**
...@@ -26,11 +33,10 @@ public class Shell { ...@@ -26,11 +33,10 @@ public class Shell {
private Connection conn; private Connection conn;
private Statement stat; private Statement stat;
private PrintStream out = System.out;
private void showUsage() { private boolean listMode;
System.out.println("java " + getClass().getName() + " [-url <url> -user <user> -password <pwd> -driver <driver]"); private int maxColumnSize = 100;
System.out.println("See also http://h2database.com/javadoc/org/h2/tools/Prompt.html"); private char boxVertical = '|'; // windows: '\u00b3';
}
/** /**
* The command line interface for this tool. The options must be split into * The command line interface for this tool. The options must be split into
...@@ -41,8 +47,8 @@ public class Shell { ...@@ -41,8 +47,8 @@ public class Shell {
* <li>-url jdbc:h2:... (database URL) </li> * <li>-url jdbc:h2:... (database URL) </li>
* <li>-user username </li> * <li>-user username </li>
* <li>-password password </li> * <li>-password password </li>
* <li>-driver driver the JDBC driver class name (not required for H2) * <li>-driver driver the JDBC driver class name (not required for most
* </li> * databases) </li>
* </ul> * </ul>
* *
* @param args the command line arguments * @param args the command line arguments
...@@ -52,6 +58,11 @@ public class Shell { ...@@ -52,6 +58,11 @@ public class Shell {
new Shell().run(args); new Shell().run(args);
} }
private void showUsage() {
out.println("java " + getClass().getName() + " [-url <url> -user <user> -password <pwd> -driver <driver]");
out.println("See also http://h2database.com/javadoc/org/h2/tools/Prompt.html");
}
private void run(String[] args) throws SQLException { private void run(String[] args) throws SQLException {
String url = null; String url = null;
String user = ""; String user = "";
...@@ -71,7 +82,7 @@ public class Shell { ...@@ -71,7 +82,7 @@ public class Shell {
throw Message.convert(e); throw Message.convert(e);
} }
} else { } else {
System.out.println("Unsupported option: " + args[i]); out.println("Unsupported option: " + args[i]);
showUsage(); showUsage();
return; return;
} }
...@@ -79,30 +90,40 @@ public class Shell { ...@@ -79,30 +90,40 @@ public class Shell {
if (url != null) { if (url != null) {
org.h2.Driver.load(); org.h2.Driver.load();
conn = DriverManager.getConnection(url, user, password); conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
} }
promptLoop(); promptLoop();
} }
private void showHelp() { private void showHelp() {
System.out.println("Commands are case insensitive; SQL statements end with ';'"); out.println("Commands are case insensitive; SQL statements end with ';'");
System.out.println("HELP or ? - Display this help"); out.println("help or ? - Display this help");
System.out.println("CONNECT - Connect to a database. Optional arguments: url, user, password"); out.println("list - Toggle result list mode");
System.out.println("DRIVER - Load a JDBC driver class (usually not required)"); out.println("maxwidth - Set maximum column width (default is 100)");
System.out.println("QUIT or EXIT - End this program"); out.println("show - List all tables");
System.out.println(); out.println("describe - Describe a table");
out.println("quit or exit - Close the connection and exit");
out.println();
} }
private void promptLoop() { private void promptLoop() {
System.out.println(); out.println();
System.out.println("Welcome to the H2 Shell " + Constants.getVersion()); out.println("Welcome to H2 Shell " + Constants.getVersion());
out.println("Exit with Ctrl+C");
if (conn != null) {
showHelp(); showHelp();
}
String statement = null; String statement = null;
while (true) { while (true) {
try { try {
if (conn == null) {
connect();
showHelp();
}
if (statement == null) { if (statement == null) {
System.out.print("sql> "); out.print("sql> ");
} else { } else {
System.out.print("...> "); out.print("...> ");
} }
String line = readLine(); String line = readLine();
if (line == null) { if (line == null) {
...@@ -121,32 +142,68 @@ public class Shell { ...@@ -121,32 +142,68 @@ public class Shell {
break; break;
} else if ("HELP".equals(upper) || "?".equals(upper)) { } else if ("HELP".equals(upper) || "?".equals(upper)) {
showHelp(); showHelp();
} else if ("LIST".equals(upper)) {
listMode = !listMode;
out.println("Result list mode is now " + (listMode ? "on" : "off"));
} else if (upper.startsWith("DESCRIBE")) {
String tableName = upper.substring("DESCRIBE".length()).trim();
if (tableName.length() == 0) {
out.println("Usage: describe <table name>");
} else { } else {
if (statement == null) { try {
if (upper.startsWith("DRIVER")) { PreparedStatement prep = conn.prepareStatement(
loadDriver(line); "SELECT CAST(COLUMN_NAME AS VARCHAR(32)) \"Column Name\", " +
} else if (upper.startsWith("CONNECT")) { "CAST(TYPE_NAME AS VARCHAR(14)) \"Type\", " +
conn = connect(line); "NUMERIC_PRECISION \"Precision\", " +
stat = conn.createStatement(); "CAST(IS_NULLABLE AS VARCHAR(8)) \"Nullable\", " +
"CAST(COLUMN_DEFAULT AS VARCHAR(20)) \"Default\" " +
"FROM INFORMATION_SCHEMA.COLUMNS " +
"WHERE UPPER(TABLE_NAME)=? ORDER BY ORDINAL_POSITION");
prep.setString(1, tableName.toUpperCase());
ResultSet rs = prep.executeQuery();
printResult(rs, false);
} catch (SQLException e) {
out.println("Exception: " + e.toString());
e.printStackTrace();
}
}
} else if (upper.startsWith("SHOW")) {
try {
ResultSet rs = stat.executeQuery(
"SELECT CAST(TABLE_SCHEMA AS VARCHAR(32)) \"Schema\", TABLE_NAME \"Table Name\" " +
"FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_SCHEMA, TABLE_NAME");
printResult(rs, false);
} catch (SQLException e) {
out.println("Exception: " + e.toString());
e.printStackTrace();
}
} else if (upper.startsWith("MAXWIDTH")) {
upper = upper.substring("MAXWIDTH".length()).trim();
try {
maxColumnSize = Integer.parseInt(upper);
} catch (Exception e) {
out.println("Usage: maxwidth <integer value>");
}
out.println("Maximum column width is now " + maxColumnSize);
} else { } else {
if (statement == null) {
statement = line; statement = line;
}
} else { } else {
statement = statement + " " + line; statement = statement + " " + line;
} }
if (end) { if (end) {
execute(statement); execute(statement, listMode);
statement = null; statement = null;
} }
} }
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("SQL Exception: " + e.getMessage()); out.println("SQL Exception: " + e.getMessage());
statement = null; statement = null;
} catch (IOException e) { } catch (IOException e) {
System.out.println(e.getMessage()); out.println(e.getMessage());
break; break;
} catch (Exception e) { } catch (Exception e) {
System.out.println("Exception: " + e.toString()); out.println("Exception: " + e.toString());
e.printStackTrace(); e.printStackTrace();
break; break;
} }
...@@ -154,59 +211,61 @@ public class Shell { ...@@ -154,59 +211,61 @@ public class Shell {
if (conn != null) { if (conn != null) {
try { try {
conn.close(); conn.close();
System.out.println("Connection closed"); out.println("Connection closed");
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("SQL Exception:"); out.println("SQL Exception:");
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
private void execute(String sql) throws SQLException { private void connect() throws IOException, SQLException {
if (stat == null) { String propertiesFileName = FileUtils.getFileInUserHome(Constants.SERVER_PROPERTIES_FILE);
System.out.println("Not connected; type CONNECT to open a connection"); String url = "jdbc:h2:~/test";
return; String user = "sa";
} String driver = null;
stat.execute(sql); try {
} Properties prop = FileUtils.loadProperties(propertiesFileName);
String data = null;
private void loadDriver(String statement) throws IOException, ClassNotFoundException, SQLException { for (int i = 0;; i++) {
StringTokenizer tokenizer = new StringTokenizer(statement); String d = prop.getProperty(String.valueOf(i));
tokenizer.nextToken(); if (d == null) {
String driver; break;
if (tokenizer.hasMoreTokens()) {
driver = tokenizer.nextToken();
} else {
System.out.print("URL: ");
driver = readLine();
} }
ClassUtils.loadUserClass(driver); data = d;
} }
if (data != null) {
private Connection connect(String statement) throws IOException, SQLException { ConnectionInfo info = new ConnectionInfo(data);
StringTokenizer tokenizer = new StringTokenizer(statement); url = info.url;
tokenizer.nextToken(); user = info.user;
String url, user, password; driver = info.driver;
if (tokenizer.hasMoreTokens()) {
url = tokenizer.nextToken();
} else {
System.out.print("URL : ");
url = readLine();
} }
if (tokenizer.hasMoreTokens()) { } catch (IOException e) {
user = tokenizer.nextToken(); // ignore
} else {
System.out.print("User : ");
user = readLine();
} }
if (tokenizer.hasMoreTokens()) { out.println("[Enter] " + url);
password = tokenizer.nextToken(); out.print("URL ");
} else { url = readLine(url);
if (driver == null) {
driver = JdbcDriverUtils.getDriver(url);
}
if (driver != null) {
out.println("[Enter] " + driver);
}
out.print("Driver ");
driver = readLine(driver);
out.println("[Enter] " + user);
out.print("User ");
user = readLine(user);
out.println("[Enter] Hide");
out.print("Password ");
String password = readLine();
if (password.length() == 0) {
password = readPassword(); password = readPassword();
} }
Connection conn = JdbcUtils.getConnection(null, url, user, password); conn = JdbcUtils.getConnection(driver, url, user, password);
System.out.println("Connected"); stat = conn.createStatement();
return conn; out.println("Connected");
} }
private String readPassword() throws IOException { private String readPassword() throws IOException {
...@@ -214,7 +273,7 @@ public class Shell { ...@@ -214,7 +273,7 @@ public class Shell {
volatile boolean stop; volatile boolean stop;
public void run() { public void run() {
while (!stop) { while (!stop) {
System.out.print("\b\b><"); out.print("\b\b><");
try { try {
Thread.sleep(10); Thread.sleep(10);
} catch (InterruptedException e) { } catch (InterruptedException e) {
...@@ -224,7 +283,7 @@ public class Shell { ...@@ -224,7 +283,7 @@ public class Shell {
} }
PasswordHider thread = new PasswordHider(); PasswordHider thread = new PasswordHider();
thread.start(); thread.start();
System.out.print("Password: > "); out.print("Password > ");
String p = readLine(); String p = readLine();
thread.stop = true; thread.stop = true;
try { try {
...@@ -232,10 +291,15 @@ public class Shell { ...@@ -232,10 +291,15 @@ public class Shell {
} catch (InterruptedException e) { } catch (InterruptedException e) {
// ignore // ignore
} }
System.out.print("\b\b"); out.print("\b\b");
return p; return p;
} }
private String readLine(String defaultValue) throws IOException {
String s = readLine();
return s.length() == 0 ? defaultValue : s;
}
private String readLine() throws IOException { private String readLine() throws IOException {
String line = new BufferedReader(new InputStreamReader(System.in)).readLine(); String line = new BufferedReader(new InputStreamReader(System.in)).readLine();
if (line == null) { if (line == null) {
...@@ -244,4 +308,122 @@ public class Shell { ...@@ -244,4 +308,122 @@ public class Shell {
return line; return line;
} }
private void execute(String sql, boolean listMode) throws SQLException {
long time = System.currentTimeMillis();
boolean result;
try {
result = stat.execute(sql);
} catch (SQLException e) {
out.println("Error: " + e.toString());
return;
}
try {
if (result) {
ResultSet rs = stat.getResultSet();
int rowCount = printResult(rs, listMode);
time = System.currentTimeMillis() - time;
out.println("(" + rowCount + (rowCount == 1 ? " row, " : " rows, ") + time + " ms)");
} else {
int updateCount = stat.getUpdateCount();
time = System.currentTimeMillis() - time;
out.println("(Update count: " + updateCount + ", " + time + " ms)");
}
} catch (SQLException e) {
out.println("Error: " + e.toString());
e.printStackTrace();
}
}
private int printResult(ResultSet rs, boolean listMode) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
int longest = 0;
int len = meta.getColumnCount();
String[] columns = new String[len];
int[] columnSizes = new int[len];
int total = 0;
for (int i = 0; i < len; i++) {
String s = meta.getColumnLabel(i + 1);
int l = s.length();
if (!listMode) {
l = Math.max(l, meta.getColumnDisplaySize(i + 1));
l = Math.min(maxColumnSize, l);
}
if (s.length() > l) {
s = s.substring(0, l);
}
columns[i] = s;
columnSizes[i] = l;
longest = Math.max(longest, l);
total += l;
}
StringBuffer buff = new StringBuffer();
if (!listMode) {
for (int i = 0; i < len; i++) {
if (i > 0) {
buff.append(boxVertical);
}
String s = columns[i];
buff.append(s);
if (i < len - 1) {
for (int j = s.length(); j < columnSizes[i]; j++) {
buff.append(' ');
}
}
}
out.println(buff.toString());
}
int rowCount = 0;
while (rs.next()) {
rowCount++;
buff.setLength(0);
if (listMode) {
if (rowCount > 1) {
out.println();
}
for (int i = 0; i < len; i++) {
if (i > 0) {
buff.append('\n');
}
String label = columns[i];
buff.append(label);
for (int j = label.length(); j < longest; j++) {
buff.append(' ');
}
buff.append(": ");
buff.append(rs.getString(i + 1));
}
} else {
for (int i = 0; i < len; i++) {
if (i > 0) {
buff.append(boxVertical);
}
String s = rs.getString(i + 1);
if (s == null) {
s = "null";
}
int m = columnSizes[i];
if (!listMode && s.length() > m) {
s = s.substring(0, m);
}
buff.append(s);
if (i < len - 1) {
for (int j = s.length(); j < m; j++) {
buff.append(' ');
}
}
}
}
out.println(buff.toString());
}
if (rowCount == 0 && listMode) {
for (int i = 0; i < len; i++) {
String label = columns[i];
buff.append(label);
buff.append('\n');
}
out.println(buff.toString());
}
return rowCount;
}
} }
...@@ -9,30 +9,50 @@ package org.h2.util; ...@@ -9,30 +9,50 @@ package org.h2.util;
* This class tries to automatically load the right JDBC driver for a given * This class tries to automatically load the right JDBC driver for a given
* database URL. * database URL.
*/ */
public class JdbcDriverLoader { public class JdbcDriverUtils {
private static final String[] DRIVERS = { private static final String[] DRIVERS = {
"jdbc:h2:", "org.h2.Driver", "jdbc:h2:", "org.h2.Driver",
"jdbc:firebirdsql:", "org.firebirdsql.jdbc.FBDriver", "jdbc:Cache:", "com.intersys.jdbc.CacheDriver",
"jdbc:daffodilDB://", "in.co.daffodil.db.rmi.RmiDaffodilDBDriver",
"jdbc:daffodil", "in.co.daffodil.db.jdbc.DaffodilDBDriver",
"jdbc:db2:", "COM.ibm.db2.jdbc.net.DB2Driver", "jdbc:db2:", "COM.ibm.db2.jdbc.net.DB2Driver",
"jdbc:oracle:", "oracle.jdbc.driver.OracleDriver", "jdbc:derby:net:", "org.apache.derby.jdbc.ClientDriver",
"jdbc:microsoft:", "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"jdbc:sqlserver:", "com.microsoft.sqlserver.jdbc.SQLServerDriver",
"jdbc:postgresql:", "org.postgresql.Driver",
"jdbc:mysql:", "com.mysql.jdbc.Driver",
"jdbc:derby://", "org.apache.derby.jdbc.ClientDriver", "jdbc:derby://", "org.apache.derby.jdbc.ClientDriver",
"jdbc:derby:", "org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:", "org.apache.derby.jdbc.EmbeddedDriver",
"jdbc:hsqldb:", "org.hsqldb.jdbcDriver" "jdbc:FrontBase:", "com.frontbase.jdbc.FBJDriver",
"jdbc:firebirdsql:", "org.firebirdsql.jdbc.FBDriver",
"jdbc:hsqldb:", "org.hsqldb.jdbcDriver",
"jdbc:informix-sqli:", "com.informix.jdbc.IfxDriver",
"jdbc:jtds:", "net.sourceforge.jtds.jdbc.Driver",
"jdbc:microsoft:", "com.microsoft.jdbc.sqlserver.SQLServerDriver",
"jdbc:mimer:", "com.mimer.jdbc.Driver",
"jdbc:mysql:", "com.mysql.jdbc.Driver",
"jdbc:odbc:", "sun.jdbc.odbc.JdbcOdbcDriver",
"jdbc:oracle:", "oracle.jdbc.driver.OracleDriver",
"jdbc:pervasive:", "com.pervasive.jdbc.v2.Driver",
"jdbc:pointbase:micro:", "com.pointbase.me.jdbc.jdbcDriver",
"jdbc:pointbase:", "com.pointbase.jdbc.jdbcUniversalDriver",
"jdbc:postgresql:", "org.postgresql.Driver",
"jdbc:sybase:", "com.sybase.jdbc3.jdbc.SybDriver",
"jdbc:sqlserver:", "com.microsoft.sqlserver.jdbc.SQLServerDriver",
}; };
public static void load(String url) throws ClassNotFoundException { public static String getDriver(String url) {
for (int i = 0; i < DRIVERS.length; i += 2) { for (int i = 0; i < DRIVERS.length; i += 2) {
String prefix = DRIVERS[i]; String prefix = DRIVERS[i];
if (url.startsWith(prefix)) { if (url.startsWith(prefix)) {
Class.forName(DRIVERS[i + 1]); return DRIVERS[i + 1];
break;
} }
} }
return null;
}
public static void load(String url) throws ClassNotFoundException {
String driver = getDriver(url);
if (driver != null) {
Class.forName(driver);
}
} }
} }
...@@ -96,7 +96,7 @@ public class JdbcUtils { ...@@ -96,7 +96,7 @@ public class JdbcUtils {
public static Connection getConnection(String driver, String url, Properties prop) throws SQLException { public static Connection getConnection(String driver, String url, Properties prop) throws SQLException {
try { try {
if (StringUtils.isNullOrEmpty(driver)) { if (StringUtils.isNullOrEmpty(driver)) {
JdbcDriverLoader.load(url); JdbcDriverUtils.load(url);
} else { } else {
Class d = ClassUtils.loadUserClass(driver); Class d = ClassUtils.loadUserClass(driver);
if (java.sql.Driver.class.isAssignableFrom(d)) { if (java.sql.Driver.class.isAssignableFrom(d)) {
......
...@@ -63,6 +63,7 @@ import org.h2.test.jdbc.TestStatement; ...@@ -63,6 +63,7 @@ import org.h2.test.jdbc.TestStatement;
import org.h2.test.jdbc.TestTransactionIsolation; import org.h2.test.jdbc.TestTransactionIsolation;
import org.h2.test.jdbc.TestUpdatableResultSet; import org.h2.test.jdbc.TestUpdatableResultSet;
import org.h2.test.jdbc.TestZloty; import org.h2.test.jdbc.TestZloty;
import org.h2.test.jdbcx.TestConnectionPool;
import org.h2.test.jdbcx.TestDataSource; import org.h2.test.jdbcx.TestDataSource;
import org.h2.test.jdbcx.TestXA; import org.h2.test.jdbcx.TestXA;
import org.h2.test.jdbcx.TestXASimple; import org.h2.test.jdbcx.TestXASimple;
...@@ -164,15 +165,6 @@ write to system table before adding to internal data structures ...@@ -164,15 +165,6 @@ write to system table before adding to internal data structures
MiniConnectionPoolManager MiniConnectionPoolManager
Hi,
Thanks a lot for your help! I can now also reproduce this problem. It only happens when using LOG=2,
and deleting or updating all rows of a table. There is a workaround (beside not using LOG=1):
System.setProperty("h2.reuseSpaceQuickly", "false");
or java -Dh2.reuseSpaceQuickly=false
I will fix this for the next release.
Regards,
Thomas
-------------- --------------
scheduler: what if invoke takes more than... scheduler: what if invoke takes more than...
...@@ -232,7 +224,8 @@ Can sometimes not delete log file? need test case ...@@ -232,7 +224,8 @@ Can sometimes not delete log file? need test case
Add where required // TODO: change in version 1.1 Add where required // TODO: change in version 1.1
History: History:
A first (experimental) implementation of a Shell tools is now included (org.h2.tools.Shell). A new Shell tools is now included (org.h2.tools.Shell) query a
database from the command line.
Performance was very slow when using LOG=2 and deleting or Performance was very slow when using LOG=2 and deleting or
updating all rows of a table in a loop. Fixed. updating all rows of a table in a loop. Fixed.
ALTER TABLE or CREATE TABLE now support parameters for the password field. ALTER TABLE or CREATE TABLE now support parameters for the password field.
...@@ -244,19 +237,13 @@ Fulltext search (native implementation): The words table is no longer ...@@ -244,19 +237,13 @@ Fulltext search (native implementation): The words table is no longer
an in-memory table because this caused memory problems in some cases. an in-memory table because this caused memory problems in some cases.
It was possible to create a role with the name as an existing user It was possible to create a role with the name as an existing user
(but not vice versa). This is not allowed any more. (but not vice versa). This is not allowed any more.
The recovery tool didn't work correctly for tables without rows.
Roadmap: Roadmap:
SET LOG_SYSTEM {NATIVE|LOG4J|COMMONS|DRIVER_MANAGER} SET LOG_SYSTEM
Fluent API for tools: Server.createTcpServer().setPort(9081).setPassword(password).start(); {NATIVE|LOG4J|COMMONS|DRIVER_MANAGER}
Fluent API for tools: Server.createTcpServer().
console features: setPort(9081).setPassword(password).start();
- reset?
- use StringBuffer to append (copy and paste problems)
- password mask option
- result set: two modes (list and table)
- Show Tables of MySQL and Show Fields (also ij)
(not required for H2) > not required for most databases
*/ */
...@@ -519,6 +506,7 @@ console features: ...@@ -519,6 +506,7 @@ console features:
new TestZloty().runTest(this); new TestZloty().runTest(this);
// jdbcx // jdbcx
new TestConnectionPool().runTest(this);
new TestDataSource().runTest(this); new TestDataSource().runTest(this);
new TestXA().runTest(this); new TestXA().runTest(this);
new TestXASimple().runTest(this); new TestXASimple().runTest(this);
......
...@@ -12,7 +12,7 @@ import java.sql.PreparedStatement; ...@@ -12,7 +12,7 @@ import java.sql.PreparedStatement;
import java.sql.Statement; import java.sql.Statement;
import java.util.HashMap; import java.util.HashMap;
import org.h2.util.JdbcDriverLoader; import org.h2.util.JdbcDriverUtils;
/** /**
* A simple wrapper around the JDBC API. * A simple wrapper around the JDBC API.
...@@ -31,7 +31,7 @@ public class Db { ...@@ -31,7 +31,7 @@ public class Db {
public static Db open(String url, String user, String password) { public static Db open(String url, String user, String password) {
try { try {
JdbcDriverLoader.load(url); JdbcDriverUtils.load(url);
return new Db(DriverManager.getConnection(url, user, password)); return new Db(DriverManager.getConnection(url, user, password));
} catch (Exception e) { } catch (Exception e) {
throw convert(e); throw convert(e);
......
package org.h2.test.jdbcx;
import java.sql.Connection;
import java.sql.Statement;
import org.h2.jdbcx.JdbcConnectionPoolManager;
import org.h2.jdbcx.JdbcDataSource;
import org.h2.test.TestBase;
public class TestConnectionPool extends TestBase {
public void test() throws Exception {
deleteDb("connectionPool");
testConnect();
testThreads();
}
private void testThreads() throws Exception {
final int len = getSize(4, 20);
final JdbcConnectionPoolManager man = getConnectionPool(len - 2);
final boolean[] stop = new boolean[1];
class TestRunner implements Runnable {
public void run() {
try {
while (!stop[0]) {
Connection conn = man.getConnection();
checkSmaller(man.getActiveConnections(), len + 1);
Statement stat = conn.createStatement();
stat.execute("SELECT 1 FROM DUAL");
conn.close();
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Thread[] threads = new Thread[len];
for (int i = 0; i < len; i++) {
threads[i] = new Thread(new TestRunner());
threads[i].start();
}
Thread.sleep(1000);
stop[0] = true;
for (int i = 0; i < len; i++) {
threads[i].join();
}
check(0, man.getActiveConnections());
man.dispose();
}
JdbcConnectionPoolManager getConnectionPool(int poolSize) throws Exception {
JdbcDataSource ds = new JdbcDataSource();
ds.setURL(getURL("connectionPool", true));
ds.setUser(getUser());
ds.setPassword(getPassword());
return new JdbcConnectionPoolManager(ds, poolSize, 2);
}
private void testConnect() throws Exception {
JdbcConnectionPoolManager man = getConnectionPool(3);
for (int i = 0; i < 100; i++) {
Connection conn = man.getConnection();
conn.close();
}
man.dispose();
}
}
...@@ -244,6 +244,7 @@ public class TestTools extends TestBase { ...@@ -244,6 +244,7 @@ public class TestTools extends TestBase {
Connection conn = DriverManager.getConnection(url, "sa", "sa"); Connection conn = DriverManager.getConnection(url, "sa", "sa");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key, name varchar, b blob, c clob)"); stat.execute("create table test(id int primary key, name varchar, b blob, c clob)");
stat.execute("create table test2(id int primary key, name varchar)");
stat.execute("insert into test values(1, 'Hello', SECURE_RAND(2000), space(2000))"); stat.execute("insert into test values(1, 'Hello', SECURE_RAND(2000), space(2000))");
ResultSet rs; ResultSet rs;
rs = stat.executeQuery("select * from test"); rs = stat.executeQuery("select * from test");
...@@ -257,6 +258,8 @@ public class TestTools extends TestBase { ...@@ -257,6 +258,8 @@ public class TestTools extends TestBase {
conn = DriverManager.getConnection(url, "another", "another"); conn = DriverManager.getConnection(url, "another", "another");
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("runscript from '" + baseDir + "/toolsRecover.data.sql'"); stat.execute("runscript from '" + baseDir + "/toolsRecover.data.sql'");
rs = stat.executeQuery("select * from test2");
checkFalse(rs.next());
rs = stat.executeQuery("select * from test"); rs = stat.executeQuery("select * from test");
rs.next(); rs.next();
check(1, rs.getInt(1)); check(1, rs.getInt(1));
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论