提交 cd697858 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 37d91a6f
......@@ -728,27 +728,29 @@ INFORMATION_SCHEMA.SETTINGS
<th>Description</th></tr>
<tr><td>h2.check</td><td>true</td><td>Assertions in the database engine</td></tr>
<tr><td>h2.check2</td><td>false</td><td>Additional assertions</td></tr>
<tr><td>h2.clientTraceDirectory</td><td>trace.db/</td><td>Directory where the trace files of the JDBC client are stored (only for client / server)</td></tr>
<tr><td>h2.emergencySpaceInitial</td><td>1048576</td><td>Size of 'reserve' file to detect disk full problems early</td></tr>
<tr><td>h2.emergencySpaceMin</td><td>131072</td><td>Minimum size of 'reserve' file</td></tr>
<tr><td>h2.lobCloseBetweenReads</td><td>false</td><td>Close LOB files between read operations</td></tr>
<tr><td>h2.lobFilesInDirectories</td><td>false</td><td>Store LOB files in subdirectories</td></tr>
<tr><td>h2.lobFilesPerDirectory</td><td>256</td><td>Maximum number of LOB files per directory</td></tr>
<tr><td>h2.logAllErrors</td><td>false</td><td>Write stack traces of any kind of error to a file</td></tr>
<tr><td>h2.logAllErrorsFile</td><td>h2errors.txt</td><td>File name to log errors</td></tr>
<tr><td>h2.maxFileRetry</td><td>16</td><td>Number of times to retry file delete and rename</td></tr>
<tr><td>h2.multiThreadedKernel</td><td>false</td><td>Allow multiple sessions to run concurrently</td></tr>
<tr><td>h2.runFinalizers</td><td>true</td><td>Run finalizers to detect unclosed connections</td></tr>
<tr><td>h2.optimizeMinMax</td><td>true</td><td>Optimize MIN and MAX aggregate functions</td></tr>
<tr><td>h2.objectCache</td><td>true</td><td>Cache commonly used objects (integers, strings)</td></tr>
<tr><td>h2.objectCacheMaxPerElementSize</td><td>4096</td><td>Maximum size of an object in the cache</td></tr>
<tr><td>h2.objectCacheSize</td><td>1024</td><td>Size of object cache</td></tr>
<tr><td>h2.optimizeIn</td><td>true</td><td>Optimize IN(...) comparisons</td></tr>
<tr><td>h2.redoBufferSize</td><td>262144</td><td>Size of the redo buffer (used at startup when recovering)</td></tr>
<tr><td>h2.recompileAlways</td><td>false</td><td>Always recompile prepared statements</td></tr>
<tr><td>h2.optimizeMinMax</td><td>true</td><td>Optimize MIN and MAX aggregate functions</td></tr>
<tr><td>h2.optimizeSubqueryCache</td><td>true</td><td>Cache subquery results</td></tr>
<tr><td>h2.overflowExceptions</td><td>true</td><td>Throw an exception on integer overflows</td></tr>
<tr><td>h2.logAllErrors</td><td>false</td><td>Write stack traces of any kind of error to a file</td></tr>
<tr><td>h2.logAllErrorsFile</td><td>h2errors.txt</td><td>File name to log errors</td></tr>
<tr><td>h2.recompileAlways</td><td>false</td><td>Always recompile prepared statements</td></tr>
<tr><td>h2.redoBufferSize</td><td>262144</td><td>Size of the redo buffer (used at startup when recovering)</td></tr>
<tr><td>h2.runFinalizers</td><td>true</td><td>Run finalizers to detect unclosed connections</td></tr>
<tr><td>h2.scriptDirectory</td><td></td><td>Relative or absolute directory where the script files are stored to or read from</td></tr>
<tr><td>h2.serverCachedObjects</td><td>64</td><td>TCP Server: number of cached objects per session</td></tr>
<tr><td>h2.serverSmallResultSetSize</td><td>100</td><td>TCP Server: result sets below this size are sent in one block</td></tr>
<tr><td>h2.emergencySpaceInitial</td><td>1048576</td><td>Size of 'reserve' file to detect disk full problems early</td></tr>
<tr><td>h2.emergencySpaceMin</td><td>131072</td><td>Minimum size of 'reserve' file</td></tr>
<tr><td>h2.objectCache</td><td>true</td><td>Cache commonly used objects (integers, strings)</td></tr>
<tr><td>h2.objectCacheSize</td><td>1024</td><td>Size of object cache</td></tr>
<tr><td>h2.objectCacheMaxPerElementSize</td><td>4096</td><td>Maximum size of an object in the cache</td></tr>
<tr><td>h2.clientTraceDirectory</td><td>trace.db/</td><td>Directory where the trace files of the JDBC client are stored (only for client / server)</td></tr>
<tr><td>h2.scriptDirectory</td><td></td><td>Relative or absolute directory where the script files are stored to or read from</td></tr>
</table>
<br /><a name="glossary_links"></a>
......
......@@ -12,33 +12,104 @@ Frequently Asked Questions
<h1>Frequently Asked Questions</h1>
<a href="#known_bugs">
Are there any known bugs? When is the next release?</a><br />
<a href="#open_source">
Is this Database Engine Open Source?</a><br />
<a href="#query_slow">
My query is slow</a><br />
<a href="#create_database">
How to Create a New Database?</a><br />
<a href="#connect">
How to Connect to a Database?</a><br />
<a href="#database_files">
Where are the Database Files Stored?</a><br />
<a href="#size_limit">
What is the Size Limit (maximum size) of a Database?</a><br />
<a href="#reliable">
Is it Reliable?</a><br />
<a href="#gcj">
Is the GCJ version stable? Faster?</a><br />
<br /><a name="known_bugs"></a>
<h3>Are there any known bugs? When is the next release?</h3>
<p>
Usually, bugs get fixes as they are found. There is a release every few weeks.
Here is the list of known and confirmed issues as of
2007-04-29:
</p>
<ul>
<li>Can not build using the test cases ant with JDK 1.3 at the moment. However most things are fixed.
</li><li>Some problems have been found with right outer join. Internally, it is converted to left outer join, which
does not always produce the correct results when used in combination with other joins.
</li></ul>
<br /><a name="open_source"></a>
<h3>Is this Database Engine Open Source?</h3>
<p>
Yes. It is free to use and distribute, and the source code is included.
See also under license.
</p>
<h3>Is the GCJ version stable? Faster?</h3>
The GCJ version is not as stable as the Java version.
When running the regression test with the GCJ version, sometimes the application just stops
at what seems to be a random point without error message.
Currently, the GCJ version is also slower than when using the Sun VM.
However, the startup of the GCJ version is faster than when using a VM.
<br /><a name="query_slow"></a>
<h3>My query is slow</h3>
<p>
Slow SELECT (or DELETE, UPDATE, MERGE) statement can have multiple reasons.
Follow this checklist:
</p>
<ul>
<li>Run ANALYSE (see documentation for details).
</li><li>Run the query with EXPLAIN and check if indexes are used (see documentation for details).
</li><li>If required, create additional indexes and try again using ANALZYE and EXPLAIN.
</li><li>If it doesn't help please report the problem.
</li>
</ul>
<br /><a name="create_database"></a>
<h3>How to Create a New Database?</h3>
<p>
By default, a new database is automatically created if it does not yet exist.
</p>
<br /><a name="connect"></a>
<h3>How to Connect to a Database?</h3>
<p>
The database driver is <code>org.h2.Driver</code>,
and the database URL starts with <code>jdbc:h2:</code>.
To connect to a database using JDBC, use the following code:
</p>
<pre>
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:test", "sa", "");
</pre>
<br /><a name="database_files"></a>
<h3>Where are the Database Files Stored?</h3>
<p>
If the base directory is not set, the database files are stored in the directory where the application is started
(the current working directory). When using the H2 Console application from the start menu, this is [Installation Directory]/bin.
The base directory can be set in the database URL. A fixed or relative path can be used. When using the URL
jdbc:h2:file:data/sample, the database is stored in the directory data (relative to the current working directory).
The directory must exist. It is also possible to use the fully qualified directory (and for Windows, drive) name.
Example: jdbc:h2:file:C:/data/test
</p>
<br /><a name="size_limit"></a>
<h3>What is the Size Limit (maximum size) of a Database?</h3>
<p>
The theoretical limit is currently 256 GB for the data. This number is excluding BLOB and CLOB data:
Every CLOB or BLOB can be up to 256 GB as well. The size limit of the index data is 256 GB as well.
</p>
<br /><a name="reliable"></a>
<h3>Is it Reliable?</h3>
<p>
That is not easy to say. It is still a quite new product. A lot of tests have been written,
and the code coverage of these tests is very high. Randomized stress tests
are run regularly. But as this is a relatively new product, there are probably
some problems that have not yet been found.
Areas that are not completely tested:
</p>
<ul>
<li>Platforms other than Windows XP and the Sun JVM 1.4
</li><li>Data types BLOB, CLOB, VARCHAR_IGNORECASE, OTHER
......@@ -54,7 +125,9 @@ Areas that are not completely tested:
</li><li>Wide indexes with large VARCHAR or VARBINARY columns and / or with a lot of columns
</li></ul>
<p>
Areas considered Experimental:
</p>
<ul>
<li>ODBC driver and the GCJ native version on Windows
</li><li>Linear Hash Index
......@@ -62,28 +135,14 @@ Areas considered Experimental:
</li><li>The ARRAY data type and related functionality.
</li></ul>
<h3>How to Create a New Database?</h3>
By default, a new database is automatically created if it does not yet exist.
<h3>How to Connect to a Database?</h3>
The database driver is <code>org.h2.Driver</code>,
and the database URL starts with <code>jdbc:h2:</code>.
To connect to a database using JDBC, use the following code:
<pre>
Class.forName("org.h2.Driver");
Connection conn = DriverManager.getConnection("jdbc:h2:test", "sa", "");
</pre>
<h3>Where are the Database Files Stored?</h3>
If the base directory is not set, the database files are stored in the directory where the application is started
(the current working directory). When using the H2 Console application from the start menu, this is [Installation Directory]/bin.
The base directory can be set in the database URL. A fixed or relative path can be used. When using the URL
jdbc:h2:file:data/sample, the database is stored in the directory data (relative to the current working directory).
The directory must exist. It is also possible to use the fully qualified directory (and for Windows, drive) name.
Example: jdbc:h2:file:C:/data/test
<h3>What is the Size Limit of a Database?</h3>
The theoretical limit is currently 256 GB for the data. This number is excluding BLOB and CLOB data:
Every CLOB or BLOB can be up to 256 GB as well. The size limit of the index data is 256 GB as well.
<br /><a name="gcj"></a>
<h3>Is the GCJ version stable? Faster?</h3>
<p>
The GCJ version is not as stable as the Java version.
When running the regression test with the GCJ version, sometimes the application just stops
at what seems to be a random point without error message.
Currently, the GCJ version is also slower than when using the Sun VM.
However, the startup of the GCJ version is faster than when using a VM.
</p>
</div></td></tr></table></body></html>
\ No newline at end of file
......@@ -232,6 +232,9 @@ It looks like the development of this database has stopped. The last release was
</tr><tr>
<td><a href="http://incubator.apache.org/openjpa">Apache OpenJPA</a></td>
<td>Open source implementation of the Java Persistence API (JPA).</td>
</tr><tr>
<td><a href="http://appfuse.org">AppFuse</a></td>
<td>Helps building web applications.</td>
</tr><tr>
<td><a href="http://bmarks-portlet.sourceforge.net">Bookmarks Portlet</a></td>
<td>JSR168 compliant bookmarks management portlet application.</td>
......@@ -253,6 +256,9 @@ It looks like the development of this database has stopped. The last release was
</tr><tr>
<td><a href="http://jamwiki.org">JAMWiki</a></td>
<td>Java-based Wiki engine.</td>
</tr><tr>
<td><a href="http://mywebpage.netscape.com/davidlbarron/javaplayer.html">JavaPlayer</a></td>
<td>Pure Java MP3 player</td>
</tr><tr>
<td><a href="http://www.jpox.org">JPOX</a></td>
<td>Java persistent objects</td>
......
......@@ -37,7 +37,24 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3>
<h3>Version 1.0 / 2007-TODO</h3><ul>
<li>In INSERT and MERGE statements, each column may only be specified once now.
<li>File names starting with ~ are now in the user directory (Java system property user.home)
</li><li>New Console starter application uses the JDK 1.6 system tray functionality if available,
or a simple AWT frame for other platforms. To try it out, execute
java org.h2.tools.Console. Feedback is welcome.
This console starter application is not the default yet,
but the plan is to remove the SysTray tool in the future.
</li><li>New method Csv.write(Writer writer, ResultSet rs)
</li><li>If a Reader or InputStream of a LOB is not closed, the LOB can not be deleted (embedded mode only).
The exception is typically 'Error while renaming file'). As a workaround, set the system property
'h2.lobCloseBetweenReads' to true to close the LOB files between read operations.
However this slows down reading.
</li><li>Server mode: the server stack trace was included in SQLException messages. Fixed.
</li><li>Views support has been partially re-implemented. Views are up to 6 times faster.
Compared to regular queries, only 20% overhead. Because this is a bigger change,
it is not enabled by default. To enable it, set the system property 'h2.indexNew' to true
(java -Dh2.indexNew=true ..., or in source code Constants.INDEX_NEW = true).
If no problems are found, this will be enabled by default in the next release.
</li><li>In INSERT and MERGE statements, each column may only be specified once now.
</li><li>For most IOExceptions now the file name is included in the error message.
</li><li>A java.util.Date object is now converted to a TIMESTAMP in the JDBC API. Previously it was converted to a DATE.
</li><li>After calling SHUTDOWN and closing the connection and a superfluous error message appeared in the trace file. Fixed.
......@@ -1312,7 +1329,6 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>Clustering: recovery needs to becomes fully automatic.
</li><li>Date: default date is '1970-01-01' (is it 1900-01-01 in the standard / other databases?)
</li><li>Test and document UPDATE TEST SET (ID, NAME) = (SELECT ID*10, NAME || '!' FROM TEST T WHERE T.ID=TEST.ID);
</li><li>Support home directory as ~ in database URL (jdbc:h2:file:~/.dir/db)
</li><li>Better space re-use in the files after deleting data (shrink the files)
</li><li>Max memory rows / max undo log size: use block count / row size not row count
</li><li>Index summary is only written if log=2; maybe write it also when log=1 and everything is fine (and no in doubt transactions)
......
......@@ -2814,7 +2814,7 @@ public class Parser {
scale = scale == -1 ? dataType.defaultScale : scale;
if(dataType.supportsPrecision || dataType.supportsScale) {
if(readIf("(")) {
precision = getPositiveInt();
precision = readLong();
if(readIf("K")) {
precision *= 1024;
} else if(readIf("M")) {
......@@ -2822,8 +2822,8 @@ public class Parser {
} else if(readIf("G")) {
precision *= 1024 * 1024 * 1024;
}
if(precision > Integer.MAX_VALUE) {
precision = Integer.MAX_VALUE;
if(precision > Long.MAX_VALUE) {
precision = Long.MAX_VALUE;
}
original += "(" + precision;
// oracle syntax
......
......@@ -4,9 +4,9 @@
*/
package org.h2.command.dml;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
......@@ -52,7 +52,7 @@ public class BackupCommand extends Prepared {
try {
String name = db.getName();
name = FileUtils.getFileName(name);
FileOutputStream zip = new FileOutputStream(fileName);
OutputStream zip = FileUtils.openFileOutputStream(fileName);
ZipOutputStream out = new ZipOutputStream(zip);
LogSystem log = db.getLog();
try {
......@@ -110,7 +110,7 @@ public class BackupCommand extends Prepared {
private void backupFile(ZipOutputStream out, String fn) throws SQLException, IOException {
out.putNextEntry(new ZipEntry(FileUtils.getFileName(fn)));
FileInputStream in = new FileInputStream(fn);
InputStream in = FileUtils.openFileInputStream(fn);
IOUtils.copyAndCloseInput(in, out);
out.closeEntry();
}
......
......@@ -6,9 +6,6 @@ package org.h2.command.dml;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
......@@ -34,8 +31,8 @@ public class ScriptBase extends Prepared implements DataHandler {
private String cipher;
private byte[] key;
private FileStore store;
private FileOutputStream outStream;
private FileInputStream inStream;
private OutputStream outStream;
private InputStream inStream;
protected OutputStream out;
protected InputStream in;
protected String fileName;
......@@ -95,7 +92,7 @@ public class ScriptBase extends Prepared implements DataHandler {
out = new BufferedOutputStream(out, Constants.IO_BUFFER_SIZE_COMPRESS);
} else {
try {
outStream = FileUtils.openFileOutputStream(new File(fileName));
outStream = FileUtils.openFileOutputStream(fileName);
} catch (IOException e) {
throw Message.convertIOException(e, fileName);
}
......@@ -110,10 +107,10 @@ public class ScriptBase extends Prepared implements DataHandler {
}
if(isEncrypted()) {
initStore();
in = new FileStoreInputStream(store, this, compressionAlgorithm != null);
in = new FileStoreInputStream(store, this, compressionAlgorithm != null, false);
} else {
try {
inStream = new FileInputStream(fileName);
inStream = FileUtils.openFileInputStream(fileName);
} catch (IOException e) {
throw Message.convertIOException(e, fileName);
}
......
......@@ -4,13 +4,11 @@
*/
package org.h2.command.dml;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
......@@ -357,28 +355,28 @@ public class ScriptCommand extends ScriptBase {
}
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT BDATA FROM SYSTEM_LOB_STREAM WHERE ID=" + id + " ORDER BY PART");
FileOutputStream out = new FileOutputStream(TEMP_LOB_FILENAME);
OutputStream out = FileUtils.openFileOutputStream(TEMP_LOB_FILENAME);
while(rs.next()) {
InputStream in = rs.getBinaryStream(1);
IOUtils.copyAndCloseInput(in, out);
}
out.close();
stat.execute("DELETE FROM SYSTEM_LOB_STREAM WHERE ID=" + id);
return new FileInputStream(TEMP_LOB_FILENAME);
return FileUtils.openFileInputStream(TEMP_LOB_FILENAME);
}
// called from the script
public static Reader combineClob(Connection conn, int id) throws SQLException, IOException {
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT CDATA FROM SYSTEM_LOB_STREAM WHERE ID=" + id + " ORDER BY PART");
FileWriter out = new FileWriter(TEMP_LOB_FILENAME);
Writer out = FileUtils.openFileWriter(TEMP_LOB_FILENAME, false);
while(rs.next()) {
Reader in = rs.getCharacterStream(1);
IOUtils.copyAndCloseInput(in, out);
}
out.close();
stat.execute("DELETE FROM SYSTEM_LOB_STREAM WHERE ID=" + id);
return new FileReader(TEMP_LOB_FILENAME);
return FileUtils.openFileReader(TEMP_LOB_FILENAME);
}
private void reset() throws SQLException {
......
......@@ -67,8 +67,8 @@ package org.h2.engine;
*/
public class Constants {
public static final int BUILD_ID = 47;
private static final String BUILD = "2007-06-13";
public static final int BUILD_ID = 48;
private static final String BUILD = "2007-06-14";
public static final int VERSION_MAJOR = 1;
public static final int VERSION_MINOR = 0;
......@@ -245,6 +245,8 @@ public class Constants {
public static final int OBJECT_CACHE_MAX_PER_ELEMENT_SIZE = getIntSetting("h2.objectCacheMaxPerElementSize", 4096);
public static final String CLIENT_TRACE_DIRECTORY = getStringSetting("h2.clientTraceDirectory", "trace.db/");
public static int MAX_FILE_RETRY = Math.max(1, getIntSetting("h2.maxFileRetry", 16));
public static boolean INDEX_NEW = getBooleanSetting("h2.indexNew", false);
public static boolean LOB_CLOSE_BETWEEN_READS = getBooleanSetting("h2.lobCloseBetweenReads", false);
public static boolean getBooleanSetting(String name, boolean defaultValue) {
String s = System.getProperty(name);
......
......@@ -4,9 +4,8 @@
*/
package org.h2.engine;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
......@@ -161,7 +160,7 @@ public class Database implements DataHandler {
MemoryFile file = FileUtils.getMemoryFile(fileName);
magic = file.getMagic();
} else {
FileInputStream fin = new FileInputStream(fileName);
InputStream fin = FileUtils.openFileInputStream(fileName);
magic = IOUtils.readBytesAndClose(fin, magicBinary.length);
}
if(ByteUtils.compareNotNull(magic, magicText) == 0) {
......@@ -1372,8 +1371,7 @@ public class Database implements DataHandler {
public String getDatabasePath() {
if(persistent) {
File parent = new File(databaseName).getAbsoluteFile();
return parent.getAbsolutePath();
return FileUtils.getAbsolutePath(databaseName);
} else {
return null;
}
......
......@@ -286,8 +286,7 @@ public class SessionRemote implements SessionInterface, DataHandler {
String message = transfer.readString();
int errorCode = transfer.readInt();
String trace = transfer.readString();
message = message + "\n" + trace;
throw new JdbcSQLException(message, sqlstate, errorCode, null);
throw new JdbcSQLException(message, sqlstate, errorCode, null, trace);
} else if(status == STATUS_CLOSED) {
transferList = null;
}
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.index;
import java.sql.SQLException;
import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Session;
import org.h2.expression.Comparison;
import org.h2.expression.Parameter;
import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.table.Column;
import org.h2.table.TableView;
import org.h2.util.IntArray;
import org.h2.util.SmallLRUCache;
import org.h2.util.ObjectArray;
import org.h2.value.Value;
public class ViewIndexNew extends Index {
private String querySQL;
private ObjectArray originalParameters;
private SmallLRUCache costCache = new SmallLRUCache(Constants.VIEW_INDEX_CACHE_SIZE);
private boolean recursive;
private int[] masks;
private String planSQL;
private Query query;
public ViewIndexNew(TableView view, String querySQL, ObjectArray originalParameters, boolean recursive) {
super(view, 0, null, null, IndexType.createNonUnique(false));
this.querySQL = querySQL;
this.originalParameters = originalParameters;
this.recursive = recursive;
columns = new Column[0];
}
public ViewIndexNew(TableView view, ViewIndexNew index, Session session, int[] masks) throws SQLException {
super(view, 0, null, null, IndexType.createNonUnique(false));
this.querySQL = index.querySQL;
this.originalParameters = index.originalParameters;
this.recursive = index.recursive;
this.masks = masks;
columns = new Column[0];
query = getQuery(session, masks);
planSQL = query.getPlanSQL();
}
public String getPlanSQL() {
return planSQL;
}
public void close(Session session) throws SQLException {
}
public void add(Session session, Row row) throws SQLException {
throw Message.getUnsupportedException();
}
public void remove(Session session, Row row) throws SQLException {
throw Message.getUnsupportedException();
}
private static class CostElement {
long evaluatedAt;
double cost;
}
public double getCost(Session session, int[] masks) throws SQLException {
IntArray masksArray = new IntArray(masks == null ? new int[0] : masks);
CostElement cachedCost = (CostElement) costCache.get(masksArray);
if(cachedCost != null) {
long time = System.currentTimeMillis();
if(time < cachedCost.evaluatedAt + Constants.VIEW_COST_CACHE_MAX_AGE) {
return cachedCost.cost;
}
}
Query query = (Query)session.prepare(querySQL, true);
if(masks == null) {
columns = new Column[0];
} else {
IntArray paramIndex = new IntArray();
for(int i=0; i<masks.length; i++) {
int mask = masks[i];
if(mask == 0) {
continue;
}
paramIndex.add(i);
}
int len = paramIndex.size();
columns = new Column[len];
for(int i=0; i<len; i++) {
int idx = paramIndex.get(i);
Column col = table.getColumn(idx);
columns[i] = col;
int mask = masks[idx];
if((mask & IndexCondition.EQUALITY) != 0) {
Parameter param = new Parameter(0);
query.addGlobalCondition(param, idx, Comparison.EQUAL);
} else {
if((mask & IndexCondition.START) != 0) {
Parameter param = new Parameter(0);
query.addGlobalCondition(param, idx, Comparison.BIGGER_EQUAL);
}
if((mask & IndexCondition.END) != 0) {
Parameter param = new Parameter(0);
query.addGlobalCondition(param, idx, Comparison.SMALLER_EQUAL);
}
}
}
if(recursive) {
return 10;
}
String sql = query.getPlanSQL();
query = (Query)session.prepare(sql);
}
double cost = query.getCost();
cachedCost = new CostElement();
cachedCost.evaluatedAt = System.currentTimeMillis();
cachedCost.cost = cost;
costCache.put(masksArray, cachedCost);
return cost;
}
public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException {
ObjectArray paramList = query.getParameters();
int idx = 0;
for(int i=0; originalParameters != null && i<originalParameters.size(); i++) {
Parameter orig = (Parameter) originalParameters.get(i);
Value value = orig.getValue(session);
Parameter param = (Parameter) paramList.get(idx++);
param.setValue(value);
}
for(int i=0; first != null && i<first.getColumnCount(); i++) {
if(first != null) {
Value v = first.getValue(i);
if(v != null) {
Parameter param = (Parameter) paramList.get(idx++);
param.setValue(v);
}
}
// for equality, only one parameter is used (first == last)
if(masks[i] != IndexCondition.EQUALITY && last != null) {
Value v = last.getValue(i);
if(v != null) {
Parameter param = (Parameter) paramList.get(idx++);
param.setValue(v);
}
}
}
LocalResult result = query.query(0);
return new ViewCursor(table, result);
}
private Query getQuery(Session session, int[] masks) throws SQLException {
Query query = (Query)session.prepare(querySQL, true);
if(masks == null) {
return query;
}
int firstIndexParam = query.getParameters().size();
IntArray paramIndex = new IntArray();
for(int i=0; i<masks.length; i++) {
int mask = masks[i];
if(mask == 0) {
continue;
}
paramIndex.add(i);
if((mask & IndexCondition.RANGE) == IndexCondition.RANGE) {
// two parameters for range queries: >= x AND <= y
paramIndex.add(i);
}
}
int len = paramIndex.size();
columns = new Column[len];
for(int i=0; i<len;) {
int idx = paramIndex.get(i);
Column col = table.getColumn(idx);
columns[i] = col;
int mask = masks[idx];
if((mask & IndexCondition.EQUALITY) == IndexCondition.EQUALITY) {
Parameter param = new Parameter(firstIndexParam + i);
query.addGlobalCondition(param, idx, Comparison.EQUAL);
i++;
} else {
if((mask & IndexCondition.START) == IndexCondition.START) {
Parameter param = new Parameter(firstIndexParam + i);
query.addGlobalCondition(param, idx, Comparison.BIGGER_EQUAL);
i++;
}
if((mask & IndexCondition.END) == IndexCondition.END) {
Parameter param = new Parameter(firstIndexParam + i);
query.addGlobalCondition(param, idx, Comparison.SMALLER_EQUAL);
i++;
}
}
}
String sql = query.getPlanSQL();
query = (Query)session.prepare(sql, true);
return query;
}
public long getCost(int[] masks) throws SQLException {
if(masks != null) {
throw Message.getUnsupportedException();
}
return Long.MAX_VALUE;
}
public void remove(Session session) throws SQLException {
throw Message.getUnsupportedException();
}
public void truncate(Session session) throws SQLException {
throw Message.getUnsupportedException();
}
public void checkRename() throws SQLException {
throw Message.getUnsupportedException();
}
public boolean needRebuild() {
return false;
}
public boolean canGetFirstOrLast(boolean first) {
return false;
}
public Value findFirstOrLast(Session session, boolean first) throws SQLException {
throw Message.getUnsupportedException();
}
public void setRecursive(boolean value) {
this.recursive = value;
}
}
......@@ -18,6 +18,7 @@ public class JdbcSQLException extends SQLException {
private static final long serialVersionUID = -8200821788226954151L;
private Throwable cause;
private String originalMessage;
private String trace;
/**
* Creates a SQLException a message, sqlstate and cause.
......@@ -26,10 +27,11 @@ public class JdbcSQLException extends SQLException {
* @param state the SQL state
* @param cause the exception that was the reason for this exception
*/
public JdbcSQLException(String message, String state, int errorCode, Throwable cause) {
public JdbcSQLException(String message, String state, int errorCode, Throwable cause, String trace) {
super(message + " [" + state + "-" + Constants.BUILD_ID + "]", state, errorCode);
this.originalMessage = message;
this.cause = cause;
this.trace = trace;
//#ifdef JDK14
initCause(cause);
//#endif
......@@ -107,5 +109,13 @@ public class JdbcSQLException extends SQLException {
public Throwable getOriginalCause() {
return cause;
}
public String toString() {
if(trace == null) {
return super.toString();
} else {
return trace;
}
}
}
......@@ -62,7 +62,7 @@ public class Message {
public static JdbcSQLException getSQLException(int errorCode, String[] param, Throwable cause) {
String sqlstate = getState(errorCode);
String message = translate(sqlstate, param);
return new JdbcSQLException(message, sqlstate, errorCode, cause);
return new JdbcSQLException(message, sqlstate, errorCode, cause, null);
}
public static SQLException getSyntaxError(String sql, int index) {
......@@ -345,9 +345,13 @@ public class Message {
}
if(e instanceof JdbcSQLException) {
JdbcSQLException j = (JdbcSQLException) e;
return new JdbcSQLException(j.getOriginalMessage()+"; SQL statement: "+sql, j.getSQLState(), j.getErrorCode(), j);
return new JdbcSQLException(j.getOriginalMessage()+"; SQL statement: "+sql,
j.getSQLState(),
j.getErrorCode(), j, null);
} else {
return new JdbcSQLException(e.getMessage()+"; SQL statement: "+sql, e.getSQLState(), e.getErrorCode(), e);
return new JdbcSQLException(e.getMessage()+"; SQL statement: "+sql,
e.getSQLState(),
e.getErrorCode(), e, null);
}
}
......
......@@ -4,15 +4,16 @@
*/
package org.h2.message;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import org.h2.engine.Constants;
import org.h2.util.FileUtils;
import org.h2.util.StringUtils;
public class TraceObject {
......@@ -183,7 +184,7 @@ public class TraceObject {
synchronized(this.getClass()) {
// e.printStackTrace();
try {
FileWriter writer = new FileWriter(Constants.LOG_ALL_ERRORS_FILE, true);
Writer writer = FileUtils.openFileWriter(Constants.LOG_ALL_ERRORS_FILE, true);
PrintWriter p = new PrintWriter(writer);
e.printStackTrace(p);
p.close();
......
......@@ -4,9 +4,9 @@
*/
package org.h2.message;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
......@@ -40,7 +40,7 @@ public class TraceSystem {
private long lastCheck;
private SmallLRUCache traces;
private SimpleDateFormat dateFormat;
private FileWriter fileWriter;
private Writer fileWriter;
private PrintWriter printWriter;
private static final int CHECK_SIZE_EACH_WRITES = 128;
private int checkSize;
......
......@@ -13,9 +13,8 @@ import java.sql.SQLException;
//#ifdef JDK14
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
......@@ -189,23 +188,24 @@ public class SecureSocketFactory {
private void setKeystore() throws IOException, SQLException {
Properties p = System.getProperties();
if (p.getProperty(KEYSTORE_KEY) == null) {
File file = FileUtils.getFileInUserHome(KEYSTORE);
String fileName = FileUtils.getFileInUserHome(KEYSTORE);
byte[] data = getKeyStoreBytes(getKeyStore(KEYSTORE_PASSWORD), KEYSTORE_PASSWORD);
boolean needWrite = true;
if (file.exists() && file.length() == data.length) {
if (FileUtils.exists(fileName) && FileUtils.length(fileName) == data.length) {
// don't need to overwrite the file if it did not change
FileInputStream fin = new FileInputStream(file);
InputStream fin = FileUtils.openFileInputStream(fileName);
byte[] now = IOUtils.readBytesAndClose(fin, 0);
if (now != null && ByteUtils.compareNotNull(data, now) == 0) {
needWrite = false;
}
}
if (needWrite) {
FileOutputStream out = new FileOutputStream(file);
OutputStream out = FileUtils.openFileOutputStream(fileName);
out.write(data);
out.close();
}
System.setProperty(KEYSTORE_KEY, file.getAbsolutePath());
String absolutePath = FileUtils.getAbsolutePath(fileName);
System.setProperty(KEYSTORE_KEY, absolutePath);
}
if (p.getProperty(KEYSTORE_PASSWORD_KEY) == null) {
System.setProperty(KEYSTORE_PASSWORD_KEY, KEYSTORE_PASSWORD);
......
......@@ -17,6 +17,7 @@ import org.h2.engine.Engine;
import org.h2.engine.Session;
import org.h2.engine.SessionRemote;
import org.h2.expression.Parameter;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.Message;
import org.h2.result.LocalResult;
import org.h2.result.ResultColumn;
......@@ -128,9 +129,15 @@ public class TcpServerThread implements Runnable {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
String trace = writer.toString();
String message;
if(e instanceof JdbcSQLException) {
message = ((JdbcSQLException) e).getOriginalMessage();
} else {
message = e.getMessage();
}
transfer.writeInt(SessionRemote.STATUS_ERROR).
writeString(s.getSQLState()).
writeString(e.getMessage()).
writeString(message).
writeInt(s.getErrorCode()).
writeString(trace).
flush();
......
......@@ -5,18 +5,19 @@
package org.h2.server.ftp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
public class FileObjectNative implements FileObject {
private File file;
static FileObjectNative get(String name) {
name = FileUtils.translateFileName(name);
return new FileObjectNative(new File(name));
}
......@@ -78,12 +79,16 @@ public class FileObjectNative implements FileObject {
}
public void write(InputStream in) throws IOException {
FileOutputStream out = new FileOutputStream(file);
IOUtils.copyAndClose(in, out);
try {
OutputStream out = FileUtils.openFileOutputStream(file.getAbsolutePath());
IOUtils.copyAndClose(in, out);
} catch(SQLException e) {
throw new IOException(e.getMessage());
}
}
public void read(long skip, OutputStream out) throws IOException {
InputStream in = new FileInputStream(file);
InputStream in = FileUtils.openFileInputStream(file.getAbsolutePath());
IOUtils.skipFully(in, skip);
IOUtils.copyAndClose(in, out);
}
......
......@@ -7,7 +7,6 @@ package org.h2.server.ftp;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
......@@ -24,6 +23,7 @@ import java.util.Properties;
import org.h2.engine.Constants;
import org.h2.server.Service;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
......@@ -155,7 +155,7 @@ public class FtpServer implements Service {
if("-ftpPort".equals(args[i])) {
port = MathUtils.decodeInt(args[++i]);
} else if("-ftpDir".equals(args[i])) {
root = args[++i];
root = FileUtils.translateFileName(args[++i]);
} else if("-ftpRead".equals(args[i])) {
readUserName = args[++i];
} else if("-ftpWrite".equals(args[i])) {
......@@ -273,8 +273,8 @@ public class FtpServer implements Service {
private void openOutput() {
if(outFile != null) {
try {
this.out = new FileOutputStream(outFile);
} catch(IOException e) {
this.out = FileUtils.openFileOutputStream(outFile);
} catch(Exception e) {
// ignore
}
outFile = null;
......
......@@ -4,10 +4,8 @@
*/
package org.h2.server.web;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -115,15 +113,15 @@ public class AppServer {
connInfoMap.remove(name);
}
private File getPropertiesFile() {
private String getPropertiesFileName() {
// store the properties in the user directory
return FileUtils.getFileInUserHome(Constants.SERVER_PROPERTIES_FILE);
}
Properties loadProperties() {
File file = getPropertiesFile();
String fileName = getPropertiesFileName();
try {
return FileUtils.loadProperties(file);
return FileUtils.loadProperties(fileName);
} catch(IOException e) {
// TODO log exception
return new Properties();
......@@ -194,10 +192,10 @@ public class AppServer {
prop.setProperty(String.valueOf(len - i - 1), info.getString());
}
}
FileOutputStream out = new FileOutputStream(getPropertiesFile());
OutputStream out = FileUtils.openFileOutputStream(getPropertiesFileName());
prop.store(out, Constants.SERVER_PROPERTIES_TITLE);
out.close();
} catch(IOException e) {
} catch(Exception e) {
TraceSystem.traceThrowable(e);
}
}
......
......@@ -33,6 +33,7 @@ public class FileLister {
* @throws SQLException
*/
public static ArrayList getDatabaseFiles(String dir, String db, boolean all) throws SQLException {
dir = FileUtils.translateFileName(dir);
ArrayList files = new ArrayList();
if(dir == null || dir.equals("")) {
dir = ".";
......
......@@ -4,9 +4,8 @@
*/
package org.h2.store;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ConnectException;
import java.net.InetAddress;
......@@ -107,16 +106,14 @@ public class FileLock {
void save() throws SQLException {
try {
File file = new File(fileName);
// TODO file: delegate to FileUtils
FileOutputStream out = FileUtils.openFileOutputStream(file);
OutputStream out = FileUtils.openFileOutputStream(fileName);
try {
properties.setProperty("method", String.valueOf(method));
properties.store(out, MAGIC);
} finally {
out.close();
}
lastWrite = file.lastModified();
lastWrite = FileUtils.getLastModified(fileName);
trace.debug("save " + properties);
} catch(IOException e) {
throw getException(e);
......@@ -125,7 +122,7 @@ public class FileLock {
private Properties load() throws SQLException {
try {
Properties p2 = FileUtils.loadProperties(new File(fileName));
Properties p2 = FileUtils.loadProperties(fileName);
trace.debug("load " + p2);
return p2;
} catch(IOException e) {
......@@ -134,9 +131,8 @@ public class FileLock {
}
private void waitUntilOld() throws SQLException {
File file = new File(fileName);
for(int i=0; i<10; i++) {
long last = file.lastModified();
long last = FileUtils.getLastModified(fileName);
long dist = System.currentTimeMillis() - last;
if(dist < -TIME_GRANULARITY) {
throw error("Lock file modified in the future: dist=" + dist);
......@@ -185,11 +181,10 @@ public class FileLock {
Thread watchdog = new Thread(new Runnable() {
public void run() {
try {
File file = new File(fileName);
while (fileName != null) {
// trace.debug("watchdog check");
try {
if (!file.exists() || file.lastModified() != lastWrite) {
if (!FileUtils.exists(fileName) || FileUtils.getLastModified(fileName) != lastWrite) {
save();
}
Thread.sleep(sleep);
......@@ -220,8 +215,7 @@ public class FileLock {
}
if (!FileUtils.createNewFile(fileName)) {
waitUntilOld();
File file = new File(fileName);
long read = file.lastModified();
long read = FileUtils.getLastModified(fileName);
Properties p2 = load();
String m2 = p2.getProperty("method", SOCKET);
if (m2.equals(FILE)) {
......@@ -255,7 +249,7 @@ public class FileLock {
throw error("IOException");
}
}
if (read != file.lastModified()) {
if (read != FileUtils.getLastModified(fileName)) {
throw error("Concurrent update");
}
FileUtils.delete(fileName);
......
......@@ -4,7 +4,6 @@
*/
package org.h2.store;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.ref.Reference;
......@@ -31,6 +30,7 @@ public class FileStore {
private Reference autoDeleteReference;
private boolean checkedWriting = true;
private boolean synchronousMode;
private String mode;
public static FileStore open(DataHandler handler, String name, String mode, byte[] magic) throws SQLException {
return open(handler, name, mode, magic, null, null, 0);
......@@ -56,16 +56,17 @@ public class FileStore {
this.handler = handler;
this.name = name;
this.magic = magic;
this.mode = mode;
try {
FileUtils.createDirs(name);
File f = new File(name);
if(f.exists() && !f.canWrite()) {
file = FileUtils.openRandomAccessFile(name, "r");
} else {
file = FileUtils.openRandomAccessFile(name, mode);
if(mode.length() > 2) {
synchronousMode = true;
}
// File f = new File(name);
if(FileUtils.exists(name) && !FileUtils.canWrite(name)) {
mode = "r";
this.mode = mode;
}
file = FileUtils.openRandomAccessFile(name, mode);
if(mode.length() > 2) {
synchronousMode = true;
}
fileLength = file.length();
} catch(IOException e) {
......@@ -325,5 +326,17 @@ public class FileStore {
public boolean isEncrypted() {
return false;
}
public void closeFile() throws IOException {
file.close();
file = null;
}
public void openFile() throws IOException {
if(file == null) {
file = FileUtils.openRandomAccessFile(name, mode);
file.seek(filePos);
}
}
}
......@@ -16,11 +16,14 @@ public class FileStoreInputStream extends InputStream {
private FileStore store;
private DataPage page;
private int remaining;
private int remainingInBuffer;
private CompressTool compress;
private boolean endOfFile;
private boolean alwaysClose;
public FileStoreInputStream(FileStore store, DataHandler handler, boolean compression) throws SQLException {
public FileStoreInputStream(FileStore store, DataHandler handler, boolean compression, boolean alwaysClose) throws SQLException {
this.store = store;
this.alwaysClose = alwaysClose;
if(compression) {
compress = CompressTool.getInstance();
}
......@@ -37,7 +40,7 @@ public class FileStoreInputStream extends InputStream {
}
public int available() {
return remaining <= 0 ? 0 : remaining;
return remainingInBuffer <= 0 ? 0 : remainingInBuffer;
}
public int read(byte[] buff) throws IOException {
......@@ -63,21 +66,22 @@ public class FileStoreInputStream extends InputStream {
public int readBlock(byte[] buff, int off, int len) throws IOException {
fillBuffer();
if(store == null) {
if(endOfFile) {
return -1;
}
int l = Math.min(remaining, len);
int l = Math.min(remainingInBuffer, len);
page.read(buff, off, l);
remaining -= l;
remainingInBuffer -= l;
return l;
}
private void fillBuffer() throws IOException {
if(remaining > 0 || store==null) {
if(remainingInBuffer > 0 || endOfFile) {
return;
}
page.reset();
try {
store.openFile();
if(store.length() == store.getFilePointer()) {
close();
return;
......@@ -87,18 +91,18 @@ public class FileStoreInputStream extends InputStream {
throw Message.convertToIOException(e);
}
page.reset();
remaining = page.readInt();
if(remaining<0) {
remainingInBuffer = page.readInt();
if(remainingInBuffer<0) {
close();
return;
}
page.checkCapacity(remaining);
page.checkCapacity(remainingInBuffer);
// get the length to read
if(compress != null) {
page.checkCapacity(page.getIntLen());
page.readInt();
}
page.setPos(page.length() + remaining);
page.setPos(page.length() + remainingInBuffer);
page.fillAligned();
int len = page.length() - Constants.FILE_BLOCK_SIZE;
page.reset();
......@@ -109,22 +113,26 @@ public class FileStoreInputStream extends InputStream {
page.readInt();
if(compress != null) {
int uncompressed = page.readInt();
byte[] buff = new byte[remaining];
page.read(buff, 0, remaining);
byte[] buff = new byte[remainingInBuffer];
page.read(buff, 0, remainingInBuffer);
page.reset();
page.checkCapacity(uncompressed);
compress.expand(buff, page.getBytes(), 0);
remaining = uncompressed;
remainingInBuffer = uncompressed;
}
} catch(SQLException e) {
throw Message.convertToIOException(e);
}
if(alwaysClose) {
store.closeFile();
}
}
public void close() throws IOException {
if(store != null) {
try {
store.close();
endOfFile = true;
} finally {
store = null;
}
......@@ -134,7 +142,7 @@ public class FileStoreInputStream extends InputStream {
protected void finalize() {
if (!Constants.RUN_FINALIZE) {
return;
}
}
try {
close();
} catch(IOException e) {
......@@ -144,11 +152,11 @@ public class FileStoreInputStream extends InputStream {
public int read() throws IOException {
fillBuffer();
if(store == null) {
if(endOfFile) {
return -1;
}
int i = page.readByte() & 0xff;
remaining--;
remainingInBuffer--;
return i;
}
......
......@@ -4,6 +4,7 @@
*/
package org.h2.store;
import java.io.IOException;
import java.sql.SQLException;
import org.h2.util.FileUtils;
......@@ -50,5 +51,11 @@ public class MemoryFileStore extends FileStore {
checkPowerOff();
memFile.write(b, off, len);
}
public void closeFile() throws IOException {
}
public void openFile() throws IOException {
}
}
......@@ -277,9 +277,11 @@ public class Column {
case Value.STRING:
case Value.STRING_IGNORECASE:
case Value.STRING_FIXED:
buff.append("(");
buff.append(precision);
buff.append(")");
if(precision < Integer.MAX_VALUE) {
buff.append("(");
buff.append(precision);
buff.append(")");
}
break;
}
}
......
......@@ -698,6 +698,7 @@ public class MetaTable extends Table {
add(rows, new String[]{"h2.clientTraceDirectory", Constants.CLIENT_TRACE_DIRECTORY});
add(rows, new String[]{"h2.scriptDirectory", Constants.SCRIPT_DIRECTORY});
add(rows, new String[]{"h2.maxFileRetry", "" + Constants.MAX_FILE_RETRY});
add(rows, new String[]{"h2.lobAlwaysClose", "" + Constants.LOB_CLOSE_BETWEEN_READS});
break;
}
case TYPE_INFO: {
......
......@@ -8,11 +8,13 @@ import java.sql.SQLException;
import org.h2.command.Prepared;
import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.index.ViewIndex;
import org.h2.index.ViewIndexNew;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.schema.Schema;
......@@ -26,7 +28,8 @@ public class TableView extends Table {
private ObjectArray tables;
private String[] columnNames;
private Query viewQuery;
private ViewIndex index;
private ViewIndex indexOld;
private ViewIndexNew indexNew;
private boolean recursive;
private SQLException createException;
......@@ -35,7 +38,12 @@ public class TableView extends Table {
this.querySQL = querySQL;
this.columnNames = columnNames;
this.recursive = recursive;
index = new ViewIndex(this, querySQL, params, recursive);
int todoRemoveIndexOld;
if(Constants.INDEX_NEW) {
indexNew = new ViewIndexNew(this, querySQL, params, recursive);
} else {
indexOld = new ViewIndex(this, querySQL, params, recursive);
}
initColumnsAndTables(session);
}
......@@ -87,7 +95,11 @@ public class TableView extends Table {
for(int i=0; i<columnNames.length; i++) {
cols[i] = new Column(columnNames[i], Value.STRING, 255, 0);
}
index.setRecursive(true);
if(Constants.INDEX_NEW) {
indexNew.setRecursive(true);
} else {
indexOld.setRecursive(true);
}
recursive = true;
createException = null;
}
......@@ -102,15 +114,15 @@ public class TableView extends Table {
public PlanItem getBestPlanItem(Session session, int[] masks) throws SQLException {
PlanItem item = new PlanItem();
item.cost = index.getCost(session, masks);
Index i2 = new ViewIndex(this, index, session, masks);
Index i2;
if(Constants.INDEX_NEW) {
item.cost = indexNew.getCost(session, masks);
i2 = new ViewIndexNew(this, indexNew, session, masks);
} else {
item.cost = indexOld.getCost(session, masks);
i2 = new ViewIndex(this, indexOld, session, masks);
}
item.setIndex(i2);
int testing;
// item.setIndex(index);
return item;
}
......@@ -204,7 +216,8 @@ public class TableView extends Table {
removeViewFromTables();
super.removeChildrenAndResources(session);
querySQL = null;
index = null;
indexNew = null;
indexOld = null;
invalidate();
}
......
......@@ -4,10 +4,9 @@
*/
package org.h2.tools;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
......@@ -86,21 +85,21 @@ public class Backup {
}
return;
}
File file = new File(zipFileName);
if(file.exists()) {
file.delete();
zipFileName = FileUtils.translateFileName(zipFileName);
if(FileUtils.exists(zipFileName)) {
FileUtils.delete(zipFileName);
}
FileOutputStream out = null;
OutputStream out = null;
try {
out = new FileOutputStream(file);
out = FileUtils.openFileOutputStream(zipFileName);
ZipOutputStream zipOut = new ZipOutputStream(out);
for(int i=0; i<list.size(); i++) {
String fileName = (String) list.get(i);
ZipEntry entry = new ZipEntry(FileUtils.getFileName(fileName));
zipOut.putNextEntry(entry);
FileInputStream in = null;
InputStream in = null;
try {
in = new FileInputStream(fileName);
in = FileUtils.openFileInputStream(fileName);
IOUtils.copyAndCloseInput(in, zipOut);
} finally {
IOUtils.closeSilently(in);
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.tools;
import java.awt.Button;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemColor;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.InputStream;
import java.sql.SQLException;
import org.h2.message.Message;
import org.h2.tools.Server;
import org.h2.util.IOUtils;
import org.h2.util.StartBrowser;
public class Console implements ActionListener, MouseListener {
private static final Font FONT = new Font("Dialog", Font.PLAIN, 11);
private Server web;
public static void main(String[] args) throws Exception {
new Console().run(args);
}
private void run(String[] args) {
try {
web = Server.createWebServer(args);
web.start();
Server.createTcpServer(args).start();
Server.createOdbcServer(args).start();
} catch (SQLException e) {
if (e.getErrorCode() == Message.EXCEPTION_OPENING_PORT_1) {
System.out.println("Port is in use, maybe another server server already running on " + web.getURL());
} else {
e.printStackTrace();
}
}
try {
createMenu();
} catch (Exception e) {
e.printStackTrace();
}
// start browser anyway (even if the server is already running)
// because some people don't look at the output,
// but are wondering why nothing happens
StartBrowser.openURL(web.getURL());
if (!web.isRunning()) {
System.exit(1);
}
}
private void createMenu() throws Exception {
InputStream in = getClass().getResourceAsStream("/org/h2/res/h2.png");
byte[] imageData = IOUtils.readBytesAndClose(in, -1);
Image image = Toolkit.getDefaultToolkit().createImage(imageData);
PopupMenu menuConsole = new PopupMenu();
MenuItem itemConsole = new MenuItem("H2 Console");
itemConsole.setActionCommand("console");
itemConsole.addActionListener(this);
itemConsole.setFont(FONT);
menuConsole.add(itemConsole);
MenuItem itemExit = new MenuItem("Exit");
itemExit.setFont(FONT);
itemExit.setActionCommand("exit");
itemExit.addActionListener(this);
menuConsole.add(itemExit);
boolean showWindow;
try {
// SystemTray.isSupported();
Boolean supported = (Boolean) Class.forName("java.awt.SystemTray").
getMethod("isSupported", new Class[0]).
invoke(null, new Object[0]);
if(!supported.booleanValue()) {
showWindow = true;
}
// TrayIcon icon = new TrayIcon(image, "H2 Database Engine", menuConsole);
Object icon = Class.forName("java.awt.TrayIcon").
getConstructor(new Class[] { Image.class, String.class, PopupMenu.class }).
newInstance(new Object[] { image, "H2 Database Engine", menuConsole });
// SystemTray tray = SystemTray.getSystemTray();
Object tray = Class.forName("java.awt.SystemTray").
getMethod("getSystemTray", new Class[0]).
invoke(null, new Object[0]);
// icon.addMouseListener(this);
icon.getClass().
getMethod("addMouseListener", new Class[]{MouseListener.class}).
invoke(icon, new Object[]{this});
// tray.add(icon);
tray.getClass().
getMethod("add", new Class[] { Class.forName("java.awt.TrayIcon") }).
invoke(tray, new Object[] { icon });
showWindow = false;
} catch (Exception e) {
showWindow = true;
}
if(showWindow) {
showWindow(image);
}
}
private void showWindow(Image image) {
Frame frame = new Frame("H2 Console");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.setIconImage(image);
frame.setResizable(false);
frame.setBackground(SystemColor.control);
GridBagLayout layout = new GridBagLayout();
frame.setLayout(layout);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.insets.left = 2;
c.insets.right = 2;
c.insets.top = 2;
c.insets.bottom = 2;
Label label = new Label("H2 Console URL:", Label.LEFT);
label.setFont(FONT);
c.anchor = GridBagConstraints.WEST;
c.gridwidth = GridBagConstraints.EAST;
frame.add(label, c);
TextField text = new TextField();
text.setEditable(false);
text.setFont(FONT);
text.setText(web.getURL());
text.setFocusable(false);
c.anchor = GridBagConstraints.EAST;
c.gridwidth = GridBagConstraints.REMAINDER;
frame.add(text, c);
Label label2 = new Label();
c.anchor = GridBagConstraints.WEST;
c.gridwidth = GridBagConstraints.EAST;
frame.add(label2, c);
Button startBrowser = new Button("Start Browser");
startBrowser.setFocusable(false);
startBrowser.setActionCommand("console");
startBrowser.addActionListener(this);
startBrowser.setFont(FONT);
c.anchor = GridBagConstraints.EAST;
c.gridwidth = GridBagConstraints.REMAINDER;
frame.add(startBrowser, c);
int width = 250, height = 120;
frame.setSize(width, height);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation((screenSize.width - width) / 2, (screenSize.height - height) / 2);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("exit")) {
System.exit(0);
} else if (e.getActionCommand().equals("console")) {
startBrowser();
}
}
private void startBrowser() {
if (web != null) {
StartBrowser.openURL(web.getURL());
}
}
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) {
startBrowser();
}
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
}
......@@ -3,14 +3,13 @@
* Initial Developer: H2 Group
*/
package org.h2.tools;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.sql.SQLException;
import org.h2.message.Message;
import org.h2.util.FileUtils;
/**
* Convert a trace file to a java class.
......@@ -73,9 +72,9 @@ public class ConvertTraceFile {
* @throws IOException
*/
private void convertFile(String traceFileName, String javaClassName, String script) throws IOException {
LineNumberReader reader = new LineNumberReader(new FileReader(traceFileName));
PrintWriter javaWriter = new PrintWriter(new FileWriter(javaClassName + ".java"));
PrintWriter scriptWriter = new PrintWriter(new FileWriter(script));
LineNumberReader reader = new LineNumberReader(FileUtils.openFileReader(traceFileName));
PrintWriter javaWriter = new PrintWriter(FileUtils.openFileWriter(javaClassName + ".java", false));
PrintWriter scriptWriter = new PrintWriter(FileUtils.openFileWriter(script, false));
javaWriter.println("import java.io.*;");
javaWriter.println("import java.sql.*;");
javaWriter.println("import java.math.*;");
......
......@@ -4,11 +4,12 @@
*/
package org.h2.tools;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.util.FileUtils;
import org.h2.util.JdbcUtils;
/**
......@@ -108,7 +109,7 @@ public class CreateCluster {
String scriptFile = "backup.sql";
Script.execute(urlSource, user, password, scriptFile);
RunScript.execute(urlTarget, user, password, scriptFile, null, false);
new File(scriptFile).delete();
FileUtils.delete(scriptFile);
// set the cluster to the serverlist on both databases
conn = DriverManager.getConnection(urlSource, user, password);
......
......@@ -8,6 +8,7 @@ import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
......@@ -29,7 +30,7 @@ public class Csv implements SimpleRowSource {
private String fileName;
private InputStream in;
private Reader reader;
private FileOutputStream out;
private OutputStream out;
private PrintWriter writer;
private int back;
private boolean endOfLine, endOfFile;
......@@ -43,20 +44,10 @@ public class Csv implements SimpleRowSource {
return new Csv();
}
/**
* Writes the result set to a file in the CSV format.
* @param fileName
* @param rs the result set
* @param charset the charset or null to use UTF-8
* @return the number of rows written
* @throws SQLException
*/
public int write(String fileName, ResultSet rs, String charset) throws SQLException {
ResultSetMetaData meta = rs.getMetaData();
init(fileName, charset);
int rows = 0;
private int writeResultSet(ResultSet rs) throws SQLException {
try {
initWrite();
ResultSetMetaData meta = rs.getMetaData();
int rows = 0;
int columnCount = meta.getColumnCount();
String[] row = new String[columnCount];
for(int i=0; i<columnCount; i++) {
......@@ -71,14 +62,42 @@ public class Csv implements SimpleRowSource {
rows++;
}
return rows;
} catch(IOException e) {
throw convertException("IOException writing file " + fileName, e);
} finally {
close();
JdbcUtils.closeSilently(rs);
}
}
/**
* Writes the result set to a file in the CSV format.
* @param writer the writer
* @param rs the result set
* @return the number of rows written
* @throws SQLException, IOException
*/
public int write(Writer writer, ResultSet rs) throws SQLException, IOException {
this.writer = new PrintWriter(writer);
return writeResultSet(rs);
}
/**
* Writes the result set to a file in the CSV format.
* @param fileName the name of the csv file
* @param rs the result set
* @param charset the charset or null to use UTF-8
* @return the number of rows written
* @throws SQLException
*/
public int write(String fileName, ResultSet rs, String charset) throws SQLException {
init(fileName, charset);
try {
initWrite();
return writeResultSet(rs);
} catch(IOException e) {
throw convertException("IOException writing " + fileName, e);
}
}
/**
* Writes the result set of a query to a file in the CSV format.
*
......@@ -112,16 +131,9 @@ public class Csv implements SimpleRowSource {
public ResultSet read(String fileName, String[] colNames, String charset) throws SQLException {
init(fileName, charset);
try {
columnNames = colNames;
initRead();
SimpleResultSet result = new SimpleResultSet(this);
makeColumnNamesUnique();
for(int i=0; i<columnNames.length; i++) {
result.addColumn(columnNames[i], Types.VARCHAR, 255, 0);
}
return result;
return readResultSet(colNames);
} catch(IOException e) {
throw convertException("IOException reading file " + fileName, e);
throw convertException("IOException reading " + fileName, e);
}
}
......@@ -134,23 +146,23 @@ public class Csv implements SimpleRowSource {
* @param reader the reader
* @param colNames or null if the column names should be read from the CSV file
* @return the result set
* @throws SQLException
* @throws SQLException, IOException
*/
public ResultSet read(Reader reader, String[] colNames) throws SQLException {
public ResultSet read(Reader reader, String[] colNames) throws SQLException, IOException {
init(null, null);
try {
this.columnNames = colNames;
this.reader = reader;
initRead();
SimpleResultSet result = new SimpleResultSet(this);
makeColumnNamesUnique();
for(int i=0; i<columnNames.length; i++) {
result.addColumn(columnNames[i], Types.VARCHAR, 255, 0);
}
return result;
} catch(IOException e) {
throw convertException("IOException", e);
this.reader = reader;
return readResultSet(colNames);
}
private ResultSet readResultSet(String[] colNames) throws SQLException, IOException {
this.columnNames = colNames;
initRead();
SimpleResultSet result = new SimpleResultSet(this);
makeColumnNamesUnique();
for(int i=0; i<columnNames.length; i++) {
result.addColumn(columnNames[i], Types.VARCHAR, 255, 0);
}
return result;
}
private void makeColumnNamesUnique() {
......@@ -243,7 +255,7 @@ public class Csv implements SimpleRowSource {
private void initRead() throws IOException {
if(reader == null) {
try {
in = new FileInputStream(fileName);
in = FileUtils.openFileInputStream(fileName);
BufferedInputStream i = new BufferedInputStream(in, bufferSize);
reader = new InputStreamReader(i, charset);
// TODO what is faster, 1, 2, 1+2
......
......@@ -8,10 +8,9 @@ import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
......@@ -274,7 +273,7 @@ public class Recover implements DataHandler {
fileName = fileName.substring(0, fileName.length()-3);
String outputFile = fileName + suffix;
System.out.println("Created file: " + outputFile);
return new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
return new PrintWriter(new BufferedWriter(FileUtils.openFileWriter(outputFile, false)));
}
private void writeDataError(PrintWriter writer, String error, byte[] data, int dumpBlocks) throws IOException {
......@@ -302,18 +301,18 @@ public class Recover implements DataHandler {
}
private void dumpLob(String fileName, boolean lobCompression) {
FileOutputStream out = null;
OutputStream out = null;
FileStore store = null;
int size = 0;
String n = fileName + (lobCompression ? ".comp" : "") + ".txt";
InputStream in = null;
try {
out = new FileOutputStream(n);
out = FileUtils.openFileOutputStream(n);
textStorage = Database.isTextStorage(fileName, false);
byte[] magic = Database.getMagic(textStorage);
store = FileStore.open(null, fileName, "r", magic);
store.init();
in = new BufferedInputStream(new FileStoreInputStream(store, this, lobCompression));
in = new BufferedInputStream(new FileStoreInputStream(store, this, lobCompression, false));
byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
while(true) {
int l = in.read(buffer);
......
......@@ -4,16 +4,16 @@
*/
package org.h2.tools;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.h2.message.Message;
import org.h2.store.FileLister;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
/*
......@@ -67,10 +67,10 @@ public class Restore {
Restore.execute(zipFileName, dir, db, quiet);
}
private static String getOriginalDbName(File file, String db) throws IOException {
FileInputStream in = null;
private static String getOriginalDbName(String fileName, String db) throws IOException {
InputStream in = null;
try {
in = new FileInputStream(file);
in = FileUtils.openFileInputStream(fileName);
ZipInputStream zipIn = new ZipInputStream(in);
String originalDbName = null;
boolean multiple = false;
......@@ -79,9 +79,9 @@ public class Restore {
if(entry == null) {
break;
}
String fileName = entry.getName();
String entryName = entry.getName();
zipIn.closeEntry();
String name = FileLister.getDatabaseNameFromFileName(fileName);
String name = FileLister.getDatabaseNameFromFileName(entryName);
if(name != null) {
if(db.equals(name)) {
originalDbName = name;
......@@ -116,20 +116,19 @@ public class Restore {
* @throws SQLException
*/
public static void execute(String zipFileName, String directory, String db, boolean quiet) throws SQLException {
FileInputStream in = null;
InputStream in = null;
try {
File file = new File(zipFileName);
if(!file.exists()) {
if(!FileUtils.exists(zipFileName)) {
throw new IOException("File not found: " + zipFileName);
}
String originalDbName = null;
if(db != null) {
originalDbName = getOriginalDbName(file, db);
originalDbName = getOriginalDbName(zipFileName, db);
if(originalDbName == null) {
throw new IOException("No database named " + db + " found");
}
}
in = new FileInputStream(file);
in = FileUtils.openFileInputStream(zipFileName);
ZipInputStream zipIn = new ZipInputStream(in);
while(true) {
ZipEntry entry = zipIn.getNextEntry();
......@@ -145,9 +144,9 @@ public class Restore {
copy = true;
}
if(copy) {
FileOutputStream out = null;
OutputStream out = null;
try {
out = new FileOutputStream(new File(directory, fileName));
out = FileUtils.openFileOutputStream(directory + "/" + fileName);
IOUtils.copy(zipIn, out);
} finally {
IOUtils.closeSilently(out);
......
......@@ -5,8 +5,6 @@
package org.h2.tools;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
......@@ -22,6 +20,7 @@ import java.util.Iterator;
import org.h2.engine.Constants;
import org.h2.message.Message;
import org.h2.util.ClassUtils;
import org.h2.util.FileUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.ScriptReader;
import org.h2.util.StringUtils;
......@@ -155,8 +154,8 @@ public class RunScript {
}
private static void execute(Connection conn, HashMap threadMap, String fileName, boolean continueOnError, String charsetName) throws SQLException, IOException {
InputStream in = new FileInputStream(fileName);
String path = new File(fileName).getAbsoluteFile().getParent();
InputStream in = FileUtils.openFileInputStream(fileName);
String path = FileUtils.getParent(fileName);
try {
BufferedInputStream bin = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE);
InputStreamReader reader = new InputStreamReader(bin, charsetName);
......@@ -177,8 +176,8 @@ public class RunScript {
sql = sql.trim();
if (sql.startsWith("@") && StringUtils.toUpperEnglish(sql).startsWith("@INCLUDE")) {
sql = sql.substring("@INCLUDE".length()).trim();
if(!new File(sql).isAbsolute()) {
sql = path + File.separator + sql;
if(!FileUtils.isAbsolute(sql)) {
sql = path + "/" + sql;
}
execute(conn, threadMap, sql, continueOnError, charsetName);
} else if (MULTI_THREAD && sql.startsWith("/*")) {
......
......@@ -5,9 +5,9 @@
package org.h2.tools;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
......@@ -15,6 +15,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import org.h2.message.Message;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.StringUtils;
......@@ -129,12 +130,12 @@ public class Script {
public static void execute(String url, String user, String password, String fileName) throws SQLException {
Connection conn = null;
Statement stat = null;
FileWriter fileWriter = null;
Writer fileWriter = null;
try {
org.h2.Driver.load();
conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement();
fileWriter = new FileWriter(fileName);
fileWriter = FileUtils.openFileWriter(fileName, false);
PrintWriter writer = new PrintWriter(new BufferedWriter(fileWriter));
ResultSet rs = stat.executeQuery("SCRIPT");
while(rs.next()) {
......
......@@ -7,9 +7,11 @@ package org.h2.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Properties;
......@@ -34,6 +36,7 @@ public class FileUtils {
// TODO gcj: use our own UTF-8 encoder
public static RandomAccessFile openRandomAccessFile(String fileName, String mode) throws IOException {
fileName = translateFileName(fileName);
try {
return new RandomAccessFile(fileName, mode);
} catch(IOException e) {
......@@ -67,6 +70,7 @@ public class FileUtils {
}
public static FileWriter openFileWriter(String fileName, boolean append) throws IOException {
fileName = translateFileName(fileName);
try {
return new FileWriter(fileName, append);
} catch(IOException e) {
......@@ -76,6 +80,7 @@ public class FileUtils {
}
public static boolean fileStartsWith(String fileName, String prefix) {
fileName = translateFileName(fileName);
if(isCaseInsensitiveFileSystem) {
fileName = StringUtils.toUpperEnglish(fileName);
prefix = StringUtils.toUpperEnglish(prefix);
......@@ -83,13 +88,20 @@ public class FileUtils {
return fileName.startsWith(prefix);
}
public static FileOutputStream openFileOutputStream(File file) throws IOException, SQLException {
public static FileInputStream openFileInputStream(String fileName) throws IOException {
fileName = translateFileName(fileName);
return new FileInputStream(fileName);
}
public static FileOutputStream openFileOutputStream(String fileName) throws IOException, SQLException {
fileName = translateFileName(fileName);
try {
File file = new File(fileName);
FileUtils.createDirs(file.getAbsolutePath());
return new FileOutputStream(file);
return new FileOutputStream(fileName);
} catch(IOException e) {
freeMemoryAndFinalize();
return new FileOutputStream(file);
return new FileOutputStream(fileName);
}
}
......@@ -108,6 +120,8 @@ public class FileUtils {
}
public static void rename(String oldName, String newName) throws SQLException {
oldName = translateFileName(oldName);
newName = translateFileName(newName);
if(isInMemory(oldName)) {
MemoryFile f = getMemoryFile(oldName);
f.setName(newName);
......@@ -135,8 +149,10 @@ public class FileUtils {
throw Message.getSQLException(Message.FILE_RENAME_FAILED_2, new String[]{oldName, newName}, null);
}
public static synchronized Properties loadProperties(File file) throws IOException {
public static synchronized Properties loadProperties(String fileName) throws IOException {
fileName = translateFileName(fileName);
Properties prop = new Properties();
File file = new File(fileName);
if(file.exists()) {
FileInputStream in = new FileInputStream(file);
try {
......@@ -169,6 +185,7 @@ public class FileUtils {
}
public static void createDirs(String fileName) throws SQLException {
fileName = translateFileName(fileName);
File f = new File(fileName);
if(!f.exists()) {
String parent = f.getParent();
......@@ -187,6 +204,7 @@ public class FileUtils {
}
public static boolean createNewFile(String fileName) throws SQLException {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
if(exists(fileName)) {
return false;
......@@ -211,6 +229,7 @@ public class FileUtils {
}
public static void delete(String fileName) throws SQLException {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
memoryFiles.remove(fileName);
return;
......@@ -242,6 +261,7 @@ public class FileUtils {
}
public static String getFileName(String name) throws SQLException {
name = translateFileName(name);
String separator = System.getProperty("file.separator");
String path = getParent(name) + separator;
String fullFileName = normalize(name);
......@@ -252,15 +272,17 @@ public class FileUtils {
return fileName;
}
public static File getFileInUserHome(String filename) {
public static String getFileInUserHome(String fileName) {
String userDir = System.getProperty("user.home");
if(userDir == null) {
return new File(filename);
return fileName;
}
return new File(userDir, filename);
File file = new File(userDir, fileName);
return file.getAbsolutePath();
}
public static String normalize(String fileName) throws SQLException {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
return fileName;
}
......@@ -273,6 +295,7 @@ public class FileUtils {
}
public static void tryDelete(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
memoryFiles.remove(fileName);
return;
......@@ -281,6 +304,7 @@ public class FileUtils {
}
public static boolean isReadOnly(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
return false;
}
......@@ -289,6 +313,7 @@ public class FileUtils {
}
public static boolean exists(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
return memoryFiles.get(fileName) != null;
}
......@@ -305,6 +330,7 @@ public class FileUtils {
}
public static long length(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
return getMemoryFile(fileName).length();
}
......@@ -316,6 +342,7 @@ public class FileUtils {
}
public static String createTempFile(String name, String suffix, boolean deleteOnExit, boolean inTempDir) throws IOException, SQLException {
name = translateFileName(name);
name += ".";
if(isInMemory(name)) {
for(int i=0;; i++) {
......@@ -344,6 +371,7 @@ public class FileUtils {
}
public static String getParent(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
return MEMORY_PREFIX;
}
......@@ -351,6 +379,7 @@ public class FileUtils {
}
public static String[] listFiles(String path) throws SQLException {
path = translateFileName(path);
if(isInMemory(path)) {
String[] list = new String[memoryFiles.size()];
MemoryFile[] l = new MemoryFile[memoryFiles.size()];
......@@ -391,6 +420,7 @@ public class FileUtils {
}
public static boolean isDirectory(String fileName) {
fileName = translateFileName(fileName);
if(isInMemory(fileName)) {
// TODO inmemory: currently doesn't support directories
return false;
......@@ -399,11 +429,13 @@ public class FileUtils {
}
public static void copy(String original, String copy) throws SQLException {
original = translateFileName(original);
copy = translateFileName(copy);
FileOutputStream out = null;
FileInputStream in = null;
try {
out = openFileOutputStream(new File(copy));
in = new FileInputStream(new File(original));
out = openFileOutputStream(copy);
in = openFileInputStream(original);
byte[] buffer = new byte[Constants.IO_BUFFER_SIZE];
while(true) {
int len = in.read(buffer);
......@@ -421,6 +453,7 @@ public class FileUtils {
}
public static void deleteRecursive(String fileName) throws SQLException {
fileName = translateFileName(fileName);
if(FileUtils.isDirectory(fileName)) {
String[] list = FileUtils.listFiles(fileName);
for(int i=0; list != null && i<list.length; i++) {
......@@ -429,5 +462,40 @@ public class FileUtils {
}
FileUtils.delete(fileName);
}
public static String translateFileName(String fileName) {
if(fileName.startsWith("~")) {
String userDir = System.getProperty("user.home");
fileName = userDir + fileName.substring(1);
}
return fileName;
}
public static boolean isAbsolute(String fileName) {
fileName = translateFileName(fileName);
File file = new File(fileName);
return file.isAbsolute();
}
public static String getAbsolutePath(String fileName) {
fileName = translateFileName(fileName);
File parent = new File(fileName).getAbsoluteFile();
return parent.getAbsolutePath();
}
public static long getLastModified(String fileName) {
fileName = translateFileName(fileName);
return new File(fileName).lastModified();
}
public static Reader openFileReader(String fileName) throws IOException {
fileName = translateFileName(fileName);
return new FileReader(fileName);
}
public static boolean canWrite(String fileName) {
fileName = translateFileName(fileName);
return new File(fileName).canWrite();
}
}
......@@ -62,7 +62,7 @@ public class Resources {
}
String name = "/" + packageName.replace('.', '/') + "/res/" + f.getName();
// System.out.println(name+": "+f.length());
FileInputStream in = new FileInputStream(f);
InputStream in = new FileInputStream(f);
byte[] buffer = IOUtils.readBytesAndClose(in, 0);
String s = ByteUtils.convertToBinString(buffer);
out.print(" Resources.add(" + StringUtils.quoteJavaString(name) + ", ");
......
......@@ -456,10 +456,10 @@ public class ValueLob extends Value {
public int hashCode() {
if (hash == 0) {
int todo;
// if(precision > 4096) {
// return (int)(precision ^ (precision >> 32));
// }
if(precision > 4096) {
// TODO: should calculate the hash code when saving, and store it in the data file
return (int)(precision ^ (precision >> 32));
}
try {
hash = ByteUtils.getByteArrayHash(getBytes());
} catch(SQLException e) {
......@@ -496,7 +496,8 @@ public class ValueLob extends Value {
return new ByteArrayInputStream(small);
}
FileStore store = handler.openFile(fileName, "r", true);
return new BufferedInputStream(new FileStoreInputStream(store, handler, compression), Constants.IO_BUFFER_SIZE);
boolean alwaysClose = Constants.LOB_CLOSE_BETWEEN_READS;
return new BufferedInputStream(new FileStoreInputStream(store, handler, compression, alwaysClose), Constants.IO_BUFFER_SIZE);
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
......
......@@ -7,7 +7,6 @@ package org.h2.test;
import java.sql.SQLException;
import java.util.Properties;
import org.h2.engine.Constants;
import org.h2.server.TcpServer;
import org.h2.test.jdbc.*;
import org.h2.test.jdbc.xa.TestXA;
......@@ -59,7 +58,7 @@ public class TestAll {
/*
Random test:
cd bin
del *.db
start cmd /k "java -cp .;%H2DRIVERS% org.h2.test.TestAll join >testJoin.txt"
......@@ -91,22 +90,15 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
public static void main(String[] args) throws Exception {
long time = System.currentTimeMillis();
TestAll test = new TestAll();
test.printSystem();
test.printSystem();
/*
Before you ask support:
Query is slow
- Run ANALYSE (see documentation for details)
Negative dictionary:
Please note that
Set h2.indexNew to false
timer test
testHalt
PostgreSQL:
--SET search_path = public, pg_catalog;
--id serial NOT NULL,
support ~ dir
Mail http://sf.net/projects/samooha
......@@ -119,7 +111,7 @@ h2\src\docsrc\html\images\SQLInjection.txt
D:\pictures\2007-email
ftp: problem with multithreading?
ftp server: problem with multithreading?
send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide,
MySQL, PostgreSQL
......@@ -129,38 +121,6 @@ try out, find bugs
Mail P2P
DROP TABLE TEST;
DROP VIEW TEST_VIEW;
CREATE TABLE TEST(ID INT PRIMARY KEY);
@LOOP 1000 INSERT INTO TEST VALUES(?);
CREATE VIEW TEST_VIEW AS SELECT * FROM TEST;
EXPLAIN SELECT * FROM TEST_VIEW WHERE ID=10;
@LOOP 1000 SELECT * FROM TEST_VIEW WHERE ID=?;
@LOOP 1000 SELECT * FROM TEST WHERE ID=?;
DROP TABLE TEST;
DROP VIEW TEST_VIEW;
CREATE TABLE TEST(
PERSON_ID INT PRIMARY KEY,
NAME VARCHAR,
LOWER_NAME VARCHAR AS LOWER(NAME)
);
CREATE INDEX IDX_NAME ON TEST(LOWER_NAME);
EXPLAIN SELECT * FROM TEST WHERE LOWER_NAME LIKE '%';
EXPLAIN SELECT * FROM TEST WHERE LOWER_NAME LIKE '%' ORDER BY LOWER_NAME;
CREATE VIEW TEST_VIEW AS SELECT * FROM TEST;
EXPLAIN SELECT * FROM TEST_VIEW WHERE LOWER_NAME LIKE '%';
EXPLAIN SELECT * FROM TEST_VIEW WHERE LOWER_NAME LIKE '%' ORDER BY LOWER_NAME;
DROP TABLE TEST;
DROP VIEW TEST_VIEW;
CREATE TABLE TEST(ID INT PRIMARY KEY);
@LOOP 1000 INSERT INTO TEST VALUES(?);
CREATE VIEW TEST_VIEW AS SELECT * FROM TEST;
EXPLAIN SELECT * FROM TEST_VIEW WHERE ID=10;
@LOOP 1000 SELECT * FROM TEST_VIEW WHERE ID=?;
@LOOP 1000 SELECT * FROM TEST WHERE ID=?;
Currently there is no such feature, however it is quite simple to add a user defined function
READ_TEXT(fileName String) returning a CLOB. The performance would probably not be optimal,
but it should work. I am not sure if this will read the CLOB in memory however.
......@@ -173,25 +133,37 @@ Add a setting to allow BigDecimal extensions
Send SQL Injection solution proposal to PostgreSQL, MySQL, Derby, HSQLDB,...
Improve ACID documentation (durability problem)
Improve LOB in directories performance
Improve documentation for MAX_LENGTH_INPLACE_LOB
Convert SQL-injection-2.txt to html document, include SQLInjection.java sample
Integrate patches from Pavel Ganelin: www.dullesopen.com/software/h2-database-03-04-07-mod.src.zip
Test Eclipse DTP 1.5 (HSQLDB / H2 connection bug fixed)
Automate real power off tests
how to make -baseDir work for H2 Console?
Maybe add a little bit AdSense
Custom Captcha for the forum, to protect against spam bots (required for Google Code?)
http://db.apache.org/ddlutils/ (write a H2 driver)
Negative dictionary:
Please note that
timer test
PostgreSQL compatibility:
--SET search_path = public, pg_catalog;
--id serial NOT NULL,
CREATE [ TEMPORARY | TEMP ] SEQUENCE name [ INCREMENT [ BY ] increment ]
[ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
[ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
http://db.apache.org/ddlutils/ (write a H2 driver)
ant docs doesn't work
*/
/*
......@@ -260,7 +232,6 @@ SELECT ID AS A FROM TEST GROUP BY ID HAVING A>0;
SELECT COUNT(*) AS A FROM TEST GROUP BY ID HAVING A>0;
-- Yes: MySQL, HSQLDB
-- Fail: Oracle, MS SQL Server, PostgreSQL, H2, Derby
*/
// TODO: fix Hibernate dialect bug / Bordea Felix (lost email)
......
......@@ -7,7 +7,6 @@ package org.h2.test.db;
import java.io.File;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
......@@ -36,7 +35,6 @@ public class TestCsv extends TestBase {
checkFalse(rs.next());
new File(BASE_DIR+"/test.csv").delete();
int testing;
// PreparedStatement prep = conn.prepareStatement("select * from csvread(?, null, ?, ?)");
// prep.setString(1, BASE_DIR+"/test.csv");
// prep.setString(2, "utf-8");
......
......@@ -15,10 +15,12 @@ import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Random;
import org.h2.engine.Constants;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
import org.h2.util.StringUtils;
......@@ -33,6 +35,7 @@ public class TestLob extends TestBase {
if(config.memory) {
return;
}
testLobNoClose();
testLobTransactions(10);
testLobTransactions(10000);
testLobRollbackStop();
......@@ -51,6 +54,38 @@ public class TestLob extends TestBase {
testJavaObject();
}
private void testLobNoClose() throws Exception {
if(config.logMode == 0 || config.networked) {
return;
}
deleteDb("lob");
Connection conn = reconnect(null);
conn.createStatement().execute("CREATE TABLE TEST(ID IDENTITY, DATA CLOB)");
conn.createStatement().execute("INSERT INTO TEST VALUES(1, SPACE(10000))");
ResultSet rs = conn.createStatement().executeQuery("SELECT DATA FROM TEST");
rs.next();
Constants.LOB_CLOSE_BETWEEN_READS = true;
Reader in = rs.getCharacterStream(1);
in.read();
conn.createStatement().execute("DELETE FROM TEST");
Constants.LOB_CLOSE_BETWEEN_READS = false;
conn.createStatement().execute("INSERT INTO TEST VALUES(1, SPACE(10000))");
rs = conn.createStatement().executeQuery("SELECT DATA FROM TEST");
rs.next();
in = rs.getCharacterStream(1);
in.read();
conn.setAutoCommit(false);
try {
conn.createStatement().execute("DELETE FROM TEST");
conn.commit();
error("Error expected");
} catch(SQLException e) {
checkNotGeneralException(e);
}
conn.rollback();
conn.close();
}
private void testLobTransactions(int spaceLen) throws Exception {
if(config.logMode == 0) {
return;
......
......@@ -824,9 +824,9 @@ create memory table a(k10 blob(10k), m20 blob(20m), g30 clob(30g));
script NODATA NOPASSWORDS NOSETTINGS drop;
> SCRIPT
> -----------------------------------------------------------------------------------------------------
> ------------------------------------------------------------------------------------------------------
> -- 0 = SELECT COUNT(*) FROM PUBLIC.A
> CREATE MEMORY TABLE PUBLIC.A( K10 BLOB(10240), M20 BLOB(20971520), G30 CLOB(2147483647) )
> CREATE MEMORY TABLE PUBLIC.A( K10 BLOB(10240), M20 BLOB(20971520), G30 CLOB(32212254720) )
> CREATE USER IF NOT EXISTS SA PASSWORD '' ADMIN
> DROP TABLE IF EXISTS PUBLIC.A
> rows: 4
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论