提交 9d04c1e4 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 5ebc40a2
...@@ -47,6 +47,8 @@ Features ...@@ -47,6 +47,8 @@ Features
Using the Trace Options</a><br /> Using the Trace Options</a><br />
<a href="#read_only"> <a href="#read_only">
Read Only Databases</a><br /> Read Only Databases</a><br />
<a href="#database_in_zip">
Read Only Databases in Zip or Jar File</a><br />
<a href="#storage_formats"> <a href="#storage_formats">
Binary and Text Storage Formats</a><br /> Binary and Text Storage Formats</a><br />
<a href="#low_disk_space"> <a href="#low_disk_space">
...@@ -358,7 +360,7 @@ This is achieved using different database URLs. The settings in the URLs are not ...@@ -358,7 +360,7 @@ This is achieved using different database URLs. The settings in the URLs are not
<td>jdbc:h2:mem:</td> <td>jdbc:h2:mem:</td>
</tr> </tr>
<tr> <tr>
<td>Database in Jar or Zip File</td> <td>Database in or Zip File</td>
<td> <td>
jdbc:h2:zip:&lt;zipFileName&gt;!/&lt;databaseName&gt;<br /> jdbc:h2:zip:&lt;zipFileName&gt;!/&lt;databaseName&gt;<br />
jdbc:h2:zip:db.zip!/test jdbc:h2:zip:db.zip!/test
...@@ -927,6 +929,29 @@ There are two ways an application can find out a database is read-only: ...@@ -927,6 +929,29 @@ There are two ways an application can find out a database is read-only:
By calling Connection.isReadOnly() or by executing the SQL statement CALL READONLY(). By calling Connection.isReadOnly() or by executing the SQL statement CALL READONLY().
</p> </p>
<br /><a name="database_in_zip"></a>
<h2>Read Only Databases in Zip or Jar File</h2>
<p>
To create a read-only database in a zip, first create a regular persistent database, and then create a backup.
If you are using a database named 'test', an easy way to do that is using the BACKUP SQL statement:
</p>
<pre>
BACKUP TO 'data.zip'
</pre>
<p>
Afterwards, you can log out, and directly open the database in the zip file using the following database URL:
</p>
<pre>
jdbc:h2:zip:data.zip!/test
</pre>
<p>
Databases in a zip file are read-only. The performance for some queries will be slower than when using
a regular database, because random access in zip files is not supported (only streaming). How much this
affects the performance depends on the queries and the data. The database
is not read in memory, so large databases are supported as well. The same indexes are used than when using
a regular database.
</p>
<br /><a name="storage_formats"></a> <br /><a name="storage_formats"></a>
<h2>Binary and Text Storage Formats</h2> <h2>Binary and Text Storage Formats</h2>
<p> <p>
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.bnf; package org.h2.bnf;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
...@@ -81,6 +82,7 @@ public class Bnf { ...@@ -81,6 +82,7 @@ public class Bnf {
} }
public void parse(Reader csv) throws Exception { public void parse(Reader csv) throws Exception {
csv = new BufferedReader(csv);
Rule functions = null; Rule functions = null;
statements = new ArrayList(); statements = new ArrayList();
ResultSet rs = Csv.getInstance().read(csv, null); ResultSet rs = Csv.getInstance().read(csv, null);
......
...@@ -138,4 +138,8 @@ public abstract class Command implements CommandInterface { ...@@ -138,4 +138,8 @@ public abstract class Command implements CommandInterface {
public void cancel() { public void cancel() {
this.cancel = true; this.cancel = true;
} }
public String toString() {
return sql;
}
} }
...@@ -171,5 +171,9 @@ public abstract class Prepared { ...@@ -171,5 +171,9 @@ public abstract class Prepared {
public int getCurrentRowNumber() { public int getCurrentRowNumber() {
return currentRowNumber; return currentRowNumber;
} }
public String toString() {
return sql;
}
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
...@@ -33,7 +34,7 @@ public class RunScriptCommand extends ScriptBase { ...@@ -33,7 +34,7 @@ public class RunScriptCommand extends ScriptBase {
try { try {
openInput(); openInput();
Reader reader = new InputStreamReader(in, charset); Reader reader = new InputStreamReader(in, charset);
ScriptReader r = new ScriptReader(reader); ScriptReader r = new ScriptReader(new BufferedReader(reader));
while (true) { while (true) {
String sql = r.readStatement(); String sql = r.readStatement();
if (sql == null) { if (sql == null) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.command.dml; package org.h2.command.dml;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
...@@ -395,7 +396,7 @@ public class ScriptCommand extends ScriptBase { ...@@ -395,7 +396,7 @@ public class ScriptCommand extends ScriptBase {
ResultSet rs = stat.executeQuery("SELECT CDATA FROM SYSTEM_LOB_STREAM WHERE ID=" + id + " ORDER BY PART"); ResultSet rs = stat.executeQuery("SELECT CDATA FROM SYSTEM_LOB_STREAM WHERE ID=" + id + " ORDER BY PART");
Writer out = FileUtils.openFileWriter(TEMP_LOB_FILENAME, false); Writer out = FileUtils.openFileWriter(TEMP_LOB_FILENAME, false);
while (rs.next()) { while (rs.next()) {
Reader in = rs.getCharacterStream(1); Reader in = new BufferedReader(rs.getCharacterStream(1));
IOUtils.copyAndCloseInput(in, out); IOUtils.copyAndCloseInput(in, out);
} }
out.close(); out.close();
......
...@@ -803,17 +803,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -803,17 +803,8 @@ public class Function extends Expression implements FunctionCall {
String fieldDelimiter = v4 == null ? null : v4.getString(); String fieldDelimiter = v4 == null ? null : v4.getString();
String escapeCharacter = v5 == null ? null : v5.getString(); String escapeCharacter = v5 == null ? null : v5.getString();
Csv csv = Csv.getInstance(); Csv csv = Csv.getInstance();
setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter, escapeCharacter);
char fieldSeparator = csv.getFieldSeparatorRead(); char fieldSeparator = csv.getFieldSeparatorRead();
if (fieldSeparatorRead != null && fieldSeparatorRead.length() > 0) {
fieldSeparator = fieldSeparatorRead.charAt(0);
csv.setFieldSeparatorRead(fieldSeparator);
}
if (fieldDelimiter != null && fieldDelimiter.length() > 0) {
csv.setFieldDelimiter(fieldDelimiter.charAt(0));
}
if (escapeCharacter != null && escapeCharacter.length() > 0) {
csv.setEscapeCharacter(escapeCharacter.charAt(0));
}
String[] columns = StringUtils.arraySplit(columnList, fieldSeparator, true); String[] columns = StringUtils.arraySplit(columnList, fieldSeparator, true);
ValueResultSet vr = ValueResultSet.get(csv.read(fileName, columns, charset)); ValueResultSet vr = ValueResultSet.get(csv.read(fileName, columns, charset));
return vr; return vr;
...@@ -835,15 +826,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -835,15 +826,7 @@ public class Function extends Expression implements FunctionCall {
String fieldDelimiter = v4 == null ? null : v4.getString(); String fieldDelimiter = v4 == null ? null : v4.getString();
String escapeCharacter = v5 == null ? null : v5.getString(); String escapeCharacter = v5 == null ? null : v5.getString();
Csv csv = Csv.getInstance(); Csv csv = Csv.getInstance();
if (fieldSeparatorWrite != null) { setCsvDelimiterEscape(csv, fieldSeparatorWrite, fieldDelimiter, escapeCharacter);
csv.setFieldSeparatorWrite(fieldSeparatorWrite);
}
if (fieldDelimiter != null && fieldDelimiter.length() > 0) {
csv.setFieldDelimiter(fieldDelimiter.charAt(0));
}
if (escapeCharacter != null && escapeCharacter.length() > 0) {
csv.setEscapeCharacter(escapeCharacter.charAt(0));
}
int rows = csv.write(conn, v0.getString(), v1.getString(), charset); int rows = csv.write(conn, v0.getString(), v1.getString(), charset);
return ValueInt.get(rows); return ValueInt.get(rows);
} }
...@@ -1606,17 +1589,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1606,17 +1589,8 @@ public class Function extends Expression implements FunctionCall {
String fieldDelimiter = args.length < 5 ? null : args[4].getValue(session).getString(); String fieldDelimiter = args.length < 5 ? null : args[4].getValue(session).getString();
String escapeCharacter = args.length < 6 ? null : args[5].getValue(session).getString(); String escapeCharacter = args.length < 6 ? null : args[5].getValue(session).getString();
Csv csv = Csv.getInstance(); Csv csv = Csv.getInstance();
char fieldSeparator = ','; setCsvDelimiterEscape(csv, fieldSeparatorRead, fieldDelimiter, escapeCharacter);
if (fieldSeparatorRead != null && fieldSeparatorRead.length() > 0) { char fieldSeparator = csv.getFieldSeparatorRead();
fieldSeparator = fieldSeparatorRead.charAt(0);
csv.setFieldSeparatorRead(fieldSeparator);
}
if (fieldDelimiter != null && fieldDelimiter.length() > 0) {
csv.setFieldDelimiter(fieldDelimiter.charAt(0));
}
if (escapeCharacter != null && escapeCharacter.length() > 0) {
csv.setEscapeCharacter(escapeCharacter.charAt(0));
}
String[] columns = StringUtils.arraySplit(columnList, fieldSeparator, true); String[] columns = StringUtils.arraySplit(columnList, fieldSeparator, true);
ResultSet rs = csv.read(fileName, columns, charset); ResultSet rs = csv.read(fileName, columns, charset);
ValueResultSet vr = ValueResultSet.getCopy(rs, 0); ValueResultSet vr = ValueResultSet.getCopy(rs, 0);
...@@ -1630,6 +1604,24 @@ public class Function extends Expression implements FunctionCall { ...@@ -1630,6 +1604,24 @@ public class Function extends Expression implements FunctionCall {
} }
return (ValueResultSet) getValueWithArgs(session, args); return (ValueResultSet) getValueWithArgs(session, args);
} }
private void setCsvDelimiterEscape(Csv csv, String fieldSeparator, String fieldDelimiter, String escapeCharacter) {
if (fieldSeparator != null) {
csv.setFieldSeparatorWrite(fieldSeparator);
if (fieldSeparator.length() > 0) {
char fs = fieldSeparator.charAt(0);
csv.setFieldSeparatorRead(fs);
}
}
if (fieldDelimiter != null) {
char fd = fieldDelimiter.length() == 0 ? 0 : fieldDelimiter.charAt(0);
csv.setFieldDelimiter(fd);
}
if (escapeCharacter != null) {
char ec = escapeCharacter.length() == 0 ? 0 : escapeCharacter.charAt(0);
csv.setEscapeCharacter(ec);
}
}
public Expression[] getArgs() { public Expression[] getArgs() {
return args; return args;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.table; package org.h2.table;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
...@@ -757,7 +758,7 @@ public class MetaTable extends Table { ...@@ -757,7 +758,7 @@ public class MetaTable extends Table {
String resource = "/org/h2/res/help.csv"; String resource = "/org/h2/res/help.csv";
try { try {
byte[] data = Resources.get(resource); byte[] data = Resources.get(resource);
Reader reader = new InputStreamReader(new ByteArrayInputStream(data)); Reader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(data)));
ResultSet rs = Csv.getInstance().read(reader, null); ResultSet rs = Csv.getInstance().read(reader, null);
for (int i = 0; rs.next(); i++) { for (int i = 0; rs.next(); i++) {
add(rows, new String[] { add(rows, new String[] {
......
...@@ -57,6 +57,7 @@ public class TableView extends Table { ...@@ -57,6 +57,7 @@ public class TableView extends Table {
throw Message.getSyntaxError(querySQL, 0); throw Message.getSyntaxError(querySQL, 0);
} }
Query query = (Query) p; Query query = (Query) p;
querySQL = query.getPlanSQL();
tables = new ObjectArray(query.getTables()); tables = new ObjectArray(query.getTables());
ObjectArray expressions = query.getExpressions(); ObjectArray expressions = query.getExpressions();
ObjectArray list = new ObjectArray(); ObjectArray list = new ObjectArray();
......
...@@ -6,6 +6,8 @@ package org.h2.tools; ...@@ -6,6 +6,8 @@ package org.h2.tools;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -221,10 +223,7 @@ public class Csv implements SimpleRowSource { ...@@ -221,10 +223,7 @@ public class Csv implements SimpleRowSource {
try { try {
OutputStream out = new FileOutputStream(fileName); OutputStream out = new FileOutputStream(fileName);
out = new BufferedOutputStream(out, bufferSize); out = new BufferedOutputStream(out, bufferSize);
writer = new PrintWriter(new OutputStreamWriter(out, charset)); writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, charset)));
// TODO performance: what is faster? one, two, or both?
// writer = new PrintWriter(new BufferedWriter(new
// OutputStreamWriter(out, encoding), bufferSize));
} catch (IOException e) { } catch (IOException e) {
close(); close();
throw e; throw e;
...@@ -283,8 +282,7 @@ public class Csv implements SimpleRowSource { ...@@ -283,8 +282,7 @@ public class Csv implements SimpleRowSource {
InputStream in = FileUtils.openFileInputStream(fileName); InputStream in = FileUtils.openFileInputStream(fileName);
in = new BufferedInputStream(in, bufferSize); in = new BufferedInputStream(in, bufferSize);
reader = new InputStreamReader(in, charset); reader = new InputStreamReader(in, charset);
// TODO what is faster, 1, 2, 1+2 reader = new BufferedReader(reader);
// reader = new BufferedReader(new InputStreamReader(in, encoding), bufferSize);
} catch (IOException e) { } catch (IOException e) {
close(); close();
throw e; throw e;
...@@ -563,6 +561,7 @@ public class Csv implements SimpleRowSource { ...@@ -563,6 +561,7 @@ public class Csv implements SimpleRowSource {
/** /**
* Set the field delimiter. The default is " (a double quote). * Set the field delimiter. The default is " (a double quote).
* 0 means no field delimiter is used.
* *
* @param fieldDelimiter the field delimiter * @param fieldDelimiter the field delimiter
*/ */
...@@ -572,6 +571,7 @@ public class Csv implements SimpleRowSource { ...@@ -572,6 +571,7 @@ public class Csv implements SimpleRowSource {
/** /**
* Get the current field delimiter. * Get the current field delimiter.
* 0 means no field delimiter is used.
* *
* @return the field delimiter * @return the field delimiter
*/ */
...@@ -581,6 +581,7 @@ public class Csv implements SimpleRowSource { ...@@ -581,6 +581,7 @@ public class Csv implements SimpleRowSource {
/** /**
* Set the escape character (used to escape the field delimiter). The default is " (a double quote). * Set the escape character (used to escape the field delimiter). The default is " (a double quote).
* 0 means no escape character is used.
* *
* @param escapeCharacter the escape character * @param escapeCharacter the escape character
*/ */
...@@ -590,6 +591,7 @@ public class Csv implements SimpleRowSource { ...@@ -590,6 +591,7 @@ public class Csv implements SimpleRowSource {
/** /**
* Get the current escape character. * Get the current escape character.
* 0 means no escape character is used.
* *
* @return the escape character * @return the escape character
*/ */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
package org.h2.tools; package org.h2.tools;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedWriter; import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
...@@ -121,14 +121,14 @@ public class Recover implements DataHandler { ...@@ -121,14 +121,14 @@ public class Recover implements DataHandler {
* INTERNAL * INTERNAL
*/ */
public static Reader readClob(String fileName) throws IOException { public static Reader readClob(String fileName) throws IOException {
return new InputStreamReader(readBlob(fileName)); return new BufferedReader(new InputStreamReader(readBlob(fileName)));
} }
/** /**
* INTERNAL * INTERNAL
*/ */
public static InputStream readBlob(String fileName) throws IOException { public static InputStream readBlob(String fileName) throws IOException {
return new FileInputStream(fileName); return new BufferedInputStream(new FileInputStream(fileName));
} }
private void removePassword(String dir, String db) throws SQLException { private void removePassword(String dir, String db) throws SQLException {
...@@ -296,7 +296,7 @@ public class Recover implements DataHandler { ...@@ -296,7 +296,7 @@ public class Recover implements DataHandler {
fileName = fileName.substring(0, fileName.length() - 3); fileName = fileName.substring(0, fileName.length() - 3);
String outputFile = fileName + suffix; String outputFile = fileName + suffix;
System.out.println("Created file: " + outputFile); System.out.println("Created file: " + outputFile);
return new PrintWriter(new BufferedWriter(FileUtils.openFileWriter(outputFile, false))); return new PrintWriter(FileUtils.openFileWriter(outputFile, false));
} }
private void writeDataError(PrintWriter writer, String error, byte[] data, int dumpBlocks) throws IOException { private void writeDataError(PrintWriter writer, String error, byte[] data, int dumpBlocks) throws IOException {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.h2.tools; package org.h2.tools;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -131,6 +132,7 @@ public class RunScript { ...@@ -131,6 +132,7 @@ public class RunScript {
* @return the last result set * @return the last result set
*/ */
public static ResultSet execute(Connection conn, Reader reader) throws SQLException { public static ResultSet execute(Connection conn, Reader reader) throws SQLException {
reader = new BufferedReader(reader);
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ResultSet rs = null; ResultSet rs = null;
ScriptReader r = new ScriptReader(reader); ScriptReader r = new ScriptReader(reader);
...@@ -156,7 +158,7 @@ public class RunScript { ...@@ -156,7 +158,7 @@ public class RunScript {
String path = FileUtils.getParent(fileName); String path = FileUtils.getParent(fileName);
try { try {
in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE); in = new BufferedInputStream(in, Constants.IO_BUFFER_SIZE);
InputStreamReader reader = new InputStreamReader(in, charsetName); Reader reader = new InputStreamReader(in, charsetName);
execute(conn, continueOnError, path, reader, charsetName); execute(conn, continueOnError, path, reader, charsetName);
} finally { } finally {
IOUtils.closeSilently(in); IOUtils.closeSilently(in);
...@@ -165,7 +167,7 @@ public class RunScript { ...@@ -165,7 +167,7 @@ public class RunScript {
private static void execute(Connection conn, boolean continueOnError, String path, Reader reader, String charsetName) throws SQLException, IOException { private static void execute(Connection conn, boolean continueOnError, String path, Reader reader, String charsetName) throws SQLException, IOException {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ScriptReader r = new ScriptReader(reader); ScriptReader r = new ScriptReader(new BufferedReader(reader));
while (true) { while (true) {
String sql = r.readStatement(); String sql = r.readStatement();
if (sql == null) { if (sql == null) {
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
*/ */
package org.h2.tools; package org.h2.tools;
import java.io.BufferedWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.Writer; import java.io.Writer;
import java.sql.Connection; import java.sql.Connection;
...@@ -134,7 +133,7 @@ public class Script { ...@@ -134,7 +133,7 @@ public class Script {
conn = DriverManager.getConnection(url, user, password); conn = DriverManager.getConnection(url, user, password);
stat = conn.createStatement(); stat = conn.createStatement();
fileWriter = FileUtils.openFileWriter(fileName, false); fileWriter = FileUtils.openFileWriter(fileName, false);
PrintWriter writer = new PrintWriter(new BufferedWriter(fileWriter)); PrintWriter writer = new PrintWriter(fileWriter);
ResultSet rs = stat.executeQuery("SCRIPT"); ResultSet rs = stat.executeQuery("SCRIPT");
while (rs.next()) { while (rs.next()) {
String s = rs.getString(1); String s = rs.getString(1);
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
*/ */
package org.h2.util; package org.h2.util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -99,7 +101,8 @@ public class FileUtils { ...@@ -99,7 +101,8 @@ public class FileUtils {
} }
public static Reader openFileReader(String fileName) throws IOException { public static Reader openFileReader(String fileName) throws IOException {
return new InputStreamReader(openFileInputStream(fileName)); Reader reader = new InputStreamReader(openFileInputStream(fileName));
return new BufferedReader(reader);
} }
public static String getFileName(String name) throws SQLException { public static String getFileName(String name) throws SQLException {
...@@ -152,7 +155,8 @@ public class FileUtils { ...@@ -152,7 +155,8 @@ public class FileUtils {
} }
public static Writer openFileWriter(String fileName, boolean append) throws SQLException { public static Writer openFileWriter(String fileName, boolean append) throws SQLException {
return new OutputStreamWriter(FileSystem.getInstance(fileName).openFileOutputStream(fileName, append)); OutputStream out = FileSystem.getInstance(fileName).openFileOutputStream(fileName, append);
return new BufferedWriter(new OutputStreamWriter(out));
} }
public static boolean fileStartsWith(String fileName, String prefix) { public static boolean fileStartsWith(String fileName, String prefix) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.util; package org.h2.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
...@@ -211,7 +212,7 @@ public class IOUtils { ...@@ -211,7 +212,7 @@ public class IOUtils {
public static Reader getReader(InputStream in) throws SQLException { public static Reader getReader(InputStream in) throws SQLException {
try { try {
// InputStreamReader may read some more bytes // InputStreamReader may read some more bytes
return in == null ? null : new InputStreamReader(in, Constants.UTF8); return in == null ? null : new BufferedReader(new InputStreamReader(in, Constants.UTF8));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw Message.convert(e); throw Message.convert(e);
} }
......
...@@ -4,12 +4,14 @@ ...@@ -4,12 +4,14 @@
*/ */
package org.h2.util; package org.h2.util;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Reader; import java.io.Reader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.engine.Constants; import org.h2.engine.Constants;
...@@ -24,7 +26,7 @@ public class ReaderInputStream extends InputStream { ...@@ -24,7 +26,7 @@ public class ReaderInputStream extends InputStream {
private final Reader reader; private final Reader reader;
private final char[] chars; private final char[] chars;
private final ByteArrayOutputStream out; private final ByteArrayOutputStream out;
private final OutputStreamWriter writer; private final Writer writer;
private int pos; private int pos;
private int remaining; private int remaining;
private byte[] buffer; private byte[] buffer;
...@@ -34,7 +36,7 @@ public class ReaderInputStream extends InputStream { ...@@ -34,7 +36,7 @@ public class ReaderInputStream extends InputStream {
this.reader = reader; this.reader = reader;
out = new ByteArrayOutputStream(Constants.IO_BUFFER_SIZE); out = new ByteArrayOutputStream(Constants.IO_BUFFER_SIZE);
try { try {
writer = new OutputStreamWriter(out, Constants.UTF8); writer = new BufferedWriter(new OutputStreamWriter(out, Constants.UTF8));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw Message.convert(e); throw Message.convert(e);
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.util; package org.h2.util;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileWriter; import java.io.FileWriter;
...@@ -35,7 +36,7 @@ public class Resources { ...@@ -35,7 +36,7 @@ public class Resources {
} }
if (new File(outDir + "/org/h2/util").exists()) { if (new File(outDir + "/org/h2/util").exists()) {
String file = outDir + "/org/h2/util/ResourceData.java"; String file = outDir + "/org/h2/util/ResourceData.java";
PrintWriter out = new PrintWriter(new FileWriter(file)); PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
out.println("package org.h2.util;"); out.println("package org.h2.util;");
out.println("// Do not change this code manually"); out.println("// Do not change this code manually");
out.println("// This code is generated by " + getClass().getName()); out.println("// This code is generated by " + getClass().getName());
......
...@@ -41,7 +41,7 @@ public class ScriptReader { ...@@ -41,7 +41,7 @@ public class ScriptReader {
if (end) { if (end) {
return null; return null;
} }
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer(200);
int c = read(); int c = read();
while (true) { while (true) {
if (c < 0) { if (c < 0) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*/ */
package org.h2.value; package org.h2.value;
import java.io.BufferedReader;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.math.BigDecimal; import java.math.BigDecimal;
...@@ -412,7 +413,11 @@ public class DataType { ...@@ -412,7 +413,11 @@ public class DataType {
v = ValueLob.createSmallLob(Value.CLOB, StringUtils.utf8Encode(rs.getString(columnIndex))); v = ValueLob.createSmallLob(Value.CLOB, StringUtils.utf8Encode(rs.getString(columnIndex)));
} else { } else {
Reader in = rs.getCharacterStream(columnIndex); Reader in = rs.getCharacterStream(columnIndex);
v = (in == null) ? (Value) ValueNull.INSTANCE : ValueLob.createClob(in, -1, session.getDataHandler()); if (in == null) {
v = ValueNull.INSTANCE;
} else {
v = ValueLob.createClob(new BufferedReader(in), -1, session.getDataHandler());
}
} }
break; break;
} }
...@@ -651,9 +656,11 @@ public class DataType { ...@@ -651,9 +656,11 @@ public class DataType {
} else if (x instanceof java.util.Date) { } else if (x instanceof java.util.Date) {
return ValueTimestamp.get(new Timestamp(((java.util.Date) x).getTime())); return ValueTimestamp.get(new Timestamp(((java.util.Date) x).getTime()));
} else if (x instanceof java.io.Reader) { } else if (x instanceof java.io.Reader) {
return ValueLob.createClob((java.io.Reader) x, -1, session.getDataHandler()); Reader r = new BufferedReader((java.io.Reader) x);
return ValueLob.createClob(r, -1, session.getDataHandler());
} else if (x instanceof java.sql.Clob) { } else if (x instanceof java.sql.Clob) {
return ValueLob.createClob(((java.sql.Clob) x).getCharacterStream(), -1, session.getDataHandler()); Reader r = new BufferedReader(((java.sql.Clob) x).getCharacterStream());
return ValueLob.createClob(r, -1, session.getDataHandler());
} else if (x instanceof java.io.InputStream) { } else if (x instanceof java.io.InputStream) {
return ValueLob.createBlob((java.io.InputStream) x, -1, session.getDataHandler()); return ValueLob.createBlob((java.io.InputStream) x, -1, session.getDataHandler());
} else if (x instanceof java.sql.Blob) { } else if (x instanceof java.sql.Blob) {
......
...@@ -6,6 +6,7 @@ package org.h2.value; ...@@ -6,6 +6,7 @@ package org.h2.value;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
...@@ -262,7 +263,7 @@ public class Transfer { ...@@ -262,7 +263,7 @@ public class Transfer {
public void flush() { public void flush() {
} }
}; };
Writer writer = new OutputStreamWriter(out2, Constants.UTF8); Writer writer = new BufferedWriter(new OutputStreamWriter(out2, Constants.UTF8));
long written = IOUtils.copyAndCloseInput(reader, writer); long written = IOUtils.copyAndCloseInput(reader, writer);
if (SysProperties.CHECK && written != length) { if (SysProperties.CHECK && written != length) {
throw Message.getInternalError("length:" + length + " written:" + written); throw Message.getInternalError("length:" + length + " written:" + written);
......
...@@ -150,47 +150,31 @@ java org.h2.test.TestAll timer ...@@ -150,47 +150,31 @@ java org.h2.test.TestAll timer
/* /*
toString() method of command, PreparedStatement to print something useful History
Now using custom toString() for most JDBC objects and commands.
Nested temporary views (SELECT * FROM (SELECT ...)) with parameters didn't work in some cases. Fixed.
History: CSV: Using an empty field delimiter didn't work (a workaround was using char(0)). Fixed.
The default value for h2.emergencySpaceInitial is now 256 KB (to speed up creating encrypted databases)
Eduardo Velasques has translated the H2 Console and the error messages to Brazilian Portuguese. Thanks a lot!
Creating a table from GROUP_CONCAT didn't work if the data was longer than 255 characters
Performance: use BufferedReader, BufferedWriter everywhere where possible (BufferInputStream alone doesn't help)
document Memory-Only databases > In-Memory Databases
By default, when the last connection to a in-memory database is closed, the contents are lost.
This can be disabled by adding this to the database URL: ;DB_CLOSE_DELAY=-1
That means to keep the contents of an in-memory database as long as the virtual machine is alive, use
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
document translation (what files to translate)
Known Problems: Known Problems:
link to history page link to history page, bug page
Creating a table from GROUP_CONCAT doesn't work if the data was longer than 255 characters Add a link to the google code bug page
GROUP_CONCAT more than 255
You are right, this is a bug. It was introduced by the getDisplaySize change. Unfortunately there is no workaround at the moment... I will fix for the next release and add a test case. I will also check if other things stopped working because of this change.
Search for 255 in whole project
CryptGenRandom.
drop table test;
create table test(id int primary key, name varchar(255));
@META select * from test;
drop table test;
ddlutils
implement & test: checkpoint commits running transactions implement & test: checkpoint commits running transactions
start writing javadocs for jdbcx package start writing javadocs for jdbcx package
Feature request: file system that writes to two file systems (for replication)
Feature request: file system with background thread writing file system (all writes)
test DbStarter test DbStarter
TestFileSystem
create table test(id int, name varchar); create table test(id int, name varchar);
insert into test select x, '' from system_range(1, 10000); insert into test select x, '' from system_range(1, 10000);
-- fast -- fast
...@@ -205,8 +189,6 @@ A file is sent although the Japanese translation has not been completed yet. ...@@ -205,8 +189,6 @@ A file is sent although the Japanese translation has not been completed yet.
At startup, when corrupted, say if LOG=0 was used before At startup, when corrupted, say if LOG=0 was used before
add more MVCC tests
slow: slow:
select ta.attname, ia.attnum, ic.relname select ta.attname, ia.attnum, ic.relname
from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class ic, pg_catalog.pg_index i, pg_catalog.pg_namespace n
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.h2.test.db; package org.h2.test.db;
import java.io.File; import java.io.File;
import java.io.FileReader;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -13,10 +14,13 @@ import java.sql.Statement; ...@@ -13,10 +14,13 @@ import java.sql.Statement;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.util.IOUtils;
import org.h2.util.StringUtils;
public class TestCsv extends TestBase { public class TestCsv extends TestBase {
public void test() throws Exception { public void test() throws Exception {
testEmptyFieldDelimiter();
testFieldDelimiter(); testFieldDelimiter();
testAsTable(); testAsTable();
testWriteRead(); testWriteRead();
...@@ -24,6 +28,29 @@ public class TestCsv extends TestBase { ...@@ -24,6 +28,29 @@ public class TestCsv extends TestBase {
testPipe(); testPipe();
} }
private void testEmptyFieldDelimiter() throws Exception {
File f = new File(baseDir + "/test.csv");
f.delete();
Connection conn = getConnection("csv");
Statement stat = conn.createStatement();
stat.execute("call csvwrite('"+baseDir+"/test.csv', 'select 1 id, ''Hello'' name', null, '|', '')");
FileReader reader = new FileReader(baseDir + "/test.csv");
String text = IOUtils.readStringAndClose(reader, -1).trim();
text = StringUtils.replaceAll(text, "\r", "");
text = StringUtils.replaceAll(text, "\n", " ");
check("ID|NAME 1|Hello", text);
ResultSet rs = stat.executeQuery("select * from csvread('" + baseDir + "/test.csv', null, null, '|', '')");
ResultSetMetaData meta = rs.getMetaData();
check(meta.getColumnCount(), 2);
check(meta.getColumnLabel(1), "ID");
check(meta.getColumnLabel(2), "NAME");
check(rs.next());
check(rs.getString(1), "1");
check(rs.getString(2), "Hello");
checkFalse(rs.next());
conn.close();
}
private void testFieldDelimiter() throws Exception { private void testFieldDelimiter() throws Exception {
File f = new File(baseDir + "/test.csv"); File f = new File(baseDir + "/test.csv");
f.delete(); f.delete();
......
...@@ -28,6 +28,7 @@ public class TestPreparedStatement extends TestBase { ...@@ -28,6 +28,7 @@ public class TestPreparedStatement extends TestBase {
deleteDb("preparedStatement"); deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement"); Connection conn = getConnection("preparedStatement");
testTempView(conn);
testInsertFunction(conn); testInsertFunction(conn);
testPrepareRecompile(conn); testPrepareRecompile(conn);
testMaxRowsChange(conn); testMaxRowsChange(conn);
...@@ -54,6 +55,30 @@ public class TestPreparedStatement extends TestBase { ...@@ -54,6 +55,30 @@ public class TestPreparedStatement extends TestBase {
conn.close(); conn.close();
} }
private void testTempView(Connection conn) throws Exception {
Statement stat = conn.createStatement();
PreparedStatement prep;
stat.execute("CREATE TABLE TEST(FLD INT PRIMARY KEY)");
stat.execute("INSERT INTO TEST VALUES(1)");
stat.execute("INSERT INTO TEST VALUES(2)");
prep = conn.prepareStatement("select FLD FROM "
+ "(select FLD FROM (SELECT FLD FROM TEST WHERE FLD = ?) AS TBL2 "
+ "WHERE TBL2.FLD = ?) AS TBL3 WHERE TBL3.FLD = ?");
prep.setInt(1, 1);
prep.setInt(2, 1);
prep.setInt(3, 1);
ResultSet rs = prep.executeQuery();
rs.next();
check(1, rs.getInt(1));
prep.setInt(1, 2);
prep.setInt(2, 2);
prep.setInt(3, 2);
rs = prep.executeQuery();
rs.next();
check(2, rs.getInt(1));
stat.execute("DROP TABLE TEST");
}
private void testInsertFunction(Connection conn) throws Exception { private void testInsertFunction(Connection conn) throws Exception {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
PreparedStatement prep; PreparedStatement prep;
......
...@@ -53,7 +53,6 @@ public class TestResultSet extends TestBase { ...@@ -53,7 +53,6 @@ public class TestResultSet extends TestBase {
testBlob(); testBlob();
testClob(); testClob();
testAutoIncrement(); testAutoIncrement();
testSerialize();
conn.close(); conn.close();
...@@ -93,12 +92,7 @@ public class TestResultSet extends TestBase { ...@@ -93,12 +92,7 @@ public class TestResultSet extends TestBase {
meta = rs.getMetaData(); meta = rs.getMetaData();
check(Integer.MAX_VALUE, meta.getColumnDisplaySize(1)); check(Integer.MAX_VALUE, meta.getColumnDisplaySize(1));
check(Integer.MAX_VALUE, meta.getPrecision(1)); check(Integer.MAX_VALUE, meta.getPrecision(1));
int todo;
}
private void testSerialize() throws Exception {
int todo;
} }
private void testLimitMaxRows() throws Exception { private void testLimitMaxRows() throws Exception {
......
...@@ -41,8 +41,8 @@ explain select * from (select dir_num, count(*) as cnt from multi_pages t, b_ho ...@@ -41,8 +41,8 @@ explain select * from (select dir_num, count(*) as cnt from multi_pages t, b_ho
where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x where t.bh_id=bh.id and bh.site='Hello' group by dir_num) as x
where cnt < 1000 order by dir_num asc; where cnt < 1000 order by dir_num asc;
> PLAN > PLAN
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ > ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> SELECT X.DIR_NUM, X.CNT FROM (select dir_num, count(*) as cnt from multi_pages t, b_holding bh where t.bh_id=bh.id and bh.site='Hello' group by dir_num) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES_TABLE_SCAN ++/ INNER JOIN PUBLIC.B_HOLDING BH /++ PUBLIC.PRIMARY_KEY_1: ID = T.BH_ID ++/ WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= CAST(?1 AS BIGINT): CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1 > SELECT X.DIR_NUM, X.CNT FROM (SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /* PUBLIC.MULTI_PAGES_TABLE_SCAN */ INNER JOIN PUBLIC.B_HOLDING BH /* PUBLIC.PRIMARY_KEY_1: ID = T.BH_ID */ WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM) X /* SELECT DIR_NUM, COUNT(*) AS CNT FROM PUBLIC.MULTI_PAGES T /++ PUBLIC.MULTI_PAGES_TABLE_SCAN ++/ INNER JOIN PUBLIC.B_HOLDING BH /++ PUBLIC.PRIMARY_KEY_1: ID = T.BH_ID ++/ WHERE (BH.SITE = 'Hello') AND (T.BH_ID = BH.ID) GROUP BY DIR_NUM HAVING COUNT(*) <= CAST(?1 AS BIGINT): CNT < 1000 */ WHERE CNT < 1000 ORDER BY 1
> rows (ordered): 1 > rows (ordered): 1
select dir_num, count(*) as cnt from multi_pages t, b_holding bh select dir_num, count(*) as cnt from multi_pages t, b_holding bh
...@@ -5163,9 +5163,9 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2; ...@@ -5163,9 +5163,9 @@ CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2;
SELECT TABLE_NAME, SQL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW'; SELECT TABLE_NAME, SQL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW';
> TABLE_NAME SQL > TABLE_NAME SQL
> ---------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------- > ---------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> TEST_ALL CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AID, A.NAME A_NAME, B.ID BID, B.NAME B_NAME FROM TEST_A A, TEST_B B WHERE A.ID = B.ID > TEST_ALL CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AS AID, A.NAME AS A_NAME, B.ID AS BID, B.NAME AS B_NAME FROM PUBLIC.TEST_A A /* PUBLIC.TEST_A_TABLE_SCAN */ INNER JOIN PUBLIC.TEST_B B /* PUBLIC.PRIMARY_KEY_2: ID = A.ID */ WHERE A.ID = B.ID
> TEST_A_SUB CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT * FROM TEST_A WHERE ID < 2 > TEST_A_SUB CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT TEST_A.ID, TEST_A.NAME FROM PUBLIC.TEST_A /* PUBLIC.PRIMARY_KEY_1: ID < 2 */ WHERE ID < 2
> rows: 2 > rows: 2
SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL; SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论