提交 3b10fe54 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 4af4dd39
......@@ -88,6 +88,11 @@ Claros inTouch</a><br />
Ajax communication suite with mail, addresses, notes, IM, and rss reader.
</p>
<p><a href="http://crashplan.com/business">
CrashPlan PRO Server</a><br />
Easy and cross platform backup solution for business and service providers.
</p>
<p><a href="http://www.dbsolo.com">
DB Solo</a><br />
SQL query tool.
......
......@@ -54,6 +54,7 @@ Roadmap
</li><li>Support OSGi: http://oscar-osgi.sourceforge.net, http://incubator.apache.org/felix/index.html
</li><li>Better space re-use in the files after deleting data (shrink the files)
</li><li>Shrink the data file without closing the database (if the end of the file is empty)
</li><li>ParameterMetaData should return correct data type where possible (INSERT, UPDATE; supported by PostgreSQL, Derby, HSQLDB)
</li><li>Full outer joins
</li><li>Procedural language / script language (Javascript)
</li><li>Change LOB mechanism (less files, keep index of lob files, point to files and row, delete unused files earlier, maybe bundle files into a tar file)
......@@ -307,7 +308,6 @@ Roadmap
</li><li>Provide an Java SQL builder with standard and H2 syntax
</li><li>Trace: write OS, file system, JVM,... when opening the database
</li><li>Trace: write dangerous operations (set log 0,...) in every case (including when opening the database)
</li><li>ParameterMetaData should return correct data type where possible (INSERT for example)
</li><li>Support indexes for views (probably requires materialized views)
</li><li>Linked tables that point to the same database should share the connection
</li><li>Document SET SEARCH_PATH, BEGIN, EXECUTE, parameters
......@@ -387,6 +387,7 @@ Roadmap
</li><li>Support NOCACHE table option (Oracle)
</li><li>Use ant 'get' to download dependencies
</li><li>Index usage for UPDATE ... WHERE .. IN (SELECT...)
</li><li>The RunScript tool should support interactive mode (reading from system in). Password using a second thread.
</li></ul>
<h2>Not Planned</h2>
......
......@@ -210,6 +210,15 @@ public class SysProperties {
*/
public static final int MAX_FILE_RETRY = Math.max(1, getIntSetting("h2.maxFileRetry", 16));
/**
* System property <code>h2.maxMemoryRowsDistinct</code> (default:
* Integer.MAX_VALUE).<br />
* The maximum number of rows kept in-memory for SELECT DISTINCT queries. If
* more than this number of rows are in a result set, a temporary table is
* used.
*/
public static final int MAX_MEMORY_ROWS_DISTINCT = getIntSetting("h2.maxMemoryRowsDistinct", Integer.MAX_VALUE);
/**
* System property <code>h2.maxQueryTimeout</code> (default: 0).<br />
* The maximum timeout of a query. The default is 0, meaning no limit.
......
......@@ -9,6 +9,7 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.h2.constant.SysProperties;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.expression.Expression;
......@@ -39,10 +40,11 @@ public class LocalResult implements ResultInterface {
private ValueHashMap distinctRows;
private Value[] currentRow;
private int offset, limit;
private ResultDiskBuffer disk;
private ResultExternal disk;
private int diskOffset;
private boolean isUpdateCount;
private int updateCount;
private boolean distinct;
public static LocalResult read(Session session, ResultSet rs, int maxrows) throws SQLException {
ObjectArray cols = getExpressionColumns(session, rs);
......@@ -97,6 +99,7 @@ public class LocalResult implements ResultInterface {
copy.rows = this.rows;
copy.sort = this.sort;
copy.distinctRows = this.distinctRows;
copy.distinct = distinct;
copy.currentRow = null;
copy.offset = 0;
copy.limit = 0;
......@@ -143,26 +146,33 @@ public class LocalResult implements ResultInterface {
}
public void setDistinct() {
// TODO big result sets: how to buffer distinct result sets?
// maybe remove duplicates when sorting each block, and when merging
distinct = true;
distinctRows = new ValueHashMap(session.getDatabase());
}
public void removeDistinct(Value[] values) throws SQLException {
if (distinctRows == null) {
if (!distinct) {
throw Message.getInternalError();
}
ValueArray array = ValueArray.get(values);
distinctRows.remove(array);
rowCount = distinctRows.size();
if (distinctRows != null) {
ValueArray array = ValueArray.get(values);
distinctRows.remove(array);
rowCount = distinctRows.size();
} else {
rowCount = disk.removeRow(values);
}
}
public boolean containsDistinct(Value[] values) throws SQLException {
if (distinctRows == null) {
if (!distinct) {
throw Message.getInternalError();
}
ValueArray array = ValueArray.get(values);
return distinctRows.get(array) != null;
if (distinctRows != null) {
ValueArray array = ValueArray.get(values);
return distinctRows.get(array) != null;
} else {
return disk.contains(values);
}
}
public void reset() throws SQLException {
......@@ -202,17 +212,26 @@ public class LocalResult implements ResultInterface {
}
public void addRow(Value[] values) throws SQLException {
if (distinctRows != null) {
ValueArray array = ValueArray.get(values);
distinctRows.put(array, values);
rowCount = distinctRows.size();
if (distinct) {
if (distinctRows != null) {
ValueArray array = ValueArray.get(values);
distinctRows.put(array, values);
rowCount = distinctRows.size();
if (rowCount > SysProperties.MAX_MEMORY_ROWS_DISTINCT) {
disk = new ResultDiskBuffer(session, sort, values.length);
disk.addRows(distinctRows.values());
distinctRows = null;
}
} else {
rowCount = disk.addRow(values);
}
return;
}
rows.add(values);
rowCount++;
if (rows.size() > maxMemoryRows && session.getDatabase().isPersistent()) {
if (disk == null) {
disk = new ResultDiskBuffer(session, sort, values.length);
disk = new ResultTempTable(session, sort, values.length);
}
addRowsToDisk();
}
......@@ -228,9 +247,11 @@ public class LocalResult implements ResultInterface {
}
public void done() throws SQLException {
if (distinctRows != null) {
rows = distinctRows.values();
distinctRows = null;
if (distinct) {
if (distinctRows != null) {
rows = distinctRows.values();
distinctRows = null;
}
}
if (disk != null) {
addRowsToDisk();
......
......@@ -12,6 +12,7 @@ import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.Message;
import org.h2.store.DataPage;
import org.h2.store.FileStore;
import org.h2.util.ObjectArray;
......@@ -20,7 +21,7 @@ import org.h2.value.Value;
/**
* This class implements the disk buffer for the LocalResult class.
*/
class ResultDiskBuffer {
class ResultDiskBuffer implements ResultExternal {
private static final int READ_AHEAD = 128;
......@@ -203,5 +204,17 @@ class ResultDiskBuffer {
file = null;
}
}
public int removeRow(Value[] values) {
throw Message.getInternalError();
}
public boolean contains(Value[] values) throws SQLException {
throw Message.getInternalError();
}
public int addRow(Value[] values) {
throw Message.getInternalError();
}
}
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.result;
import java.sql.SQLException;
import org.h2.util.ObjectArray;
import org.h2.value.Value;
/**
* This interface is used to extend the LocalResult class, if data does not fit
* in memory.
*/
public interface ResultExternal {
void reset() throws SQLException;
Value[] next() throws SQLException;
void addRows(ObjectArray rows) throws SQLException;
void done() throws SQLException;
void close();
int removeRow(Value[] values) throws SQLException;
boolean contains(Value[] values) throws SQLException;
int addRow(Value[] values) throws SQLException;
}
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.result;
import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.engine.Session;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.schema.Schema;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.TableData;
import org.h2.util.ObjectArray;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueUuid;
/**
* This class implements the temp table buffer for the LocalResult class.
*/
public class ResultTempTable implements ResultExternal {
private static final String COLUMN_NAME = "DATA";
private Session session;
private TableData table;
private SortOrder sort;
private Index index;
private Cursor cursor;
public ResultTempTable(Session session, SortOrder sort, int columnCount) throws SQLException {
this.session = session;
this.sort = sort;
String tableName = "TEMP_" + ValueUuid.getNewRandom().toString();
Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN);
Column column = new Column(COLUMN_NAME, Value.ARRAY);
column.setNullable(false);
ObjectArray columns = new ObjectArray();
columns.add(column);
int tableId = session.getDatabase().allocateObjectId(true, true);
table = schema.createTable(tableName, tableId, columns, false, false);
int indexId = session.getDatabase().allocateObjectId(true, true);
IndexColumn indexColumn = new IndexColumn();
indexColumn.column = column;
indexColumn.columnName = COLUMN_NAME;
IndexType indexType;
indexType = IndexType.createPrimaryKey(true, false);
IndexColumn[] indexCols = new IndexColumn[]{indexColumn};
index = table.addIndex(session, tableName, indexId, indexCols, indexType, Index.EMPTY_HEAD, null);
}
public int removeRow(Value[] values) throws SQLException {
ValueArray data = ValueArray.get(values);
Row row = new Row(new Value[]{data}, data.getMemory());
table.removeRow(session, row);
return (int) table.getRowCount(session);
}
public boolean contains(Value[] values) throws SQLException {
ValueArray data = ValueArray.get(values);
Row row = new Row(new Value[]{data}, data.getMemory());
Cursor cursor = index.find(session, row, row);
return cursor.next();
}
public int addRow(Value[] values) throws SQLException {
ValueArray data = ValueArray.get(values);
Row row = new Row(new Value[]{data}, data.getMemory());
table.addRow(session, row);
return (int) table.getRowCount(session);
}
public void addRows(ObjectArray rows) throws SQLException {
if (sort != null) {
sort.sort(rows);
}
for (int i = 0; i < rows.size(); i++) {
Value[] values = (Value[]) rows.get(i);
addRow(values);
}
}
public void close() {
int todo;
try {
index.remove(session);
table.removeChildrenAndResources(session);
} catch (SQLException e) {
int test;
e.printStackTrace();
}
}
public void done() throws SQLException {
}
public Value[] next() throws SQLException {
if (!cursor.next()) {
return null;
}
Row row = cursor.get();
ValueArray data = (ValueArray) row.getValue(0);
return data.getList();
}
public void reset() throws SQLException {
cursor = index.find(session, null, null);
}
}
......@@ -23,6 +23,7 @@ import java.net.Socket;
import java.security.SecureClassLoader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
......@@ -1558,6 +1559,11 @@ class WebThread extends Thread implements DatabaseEventListener {
buff.append("${text.result.noRunningStatement}");
}
return buff.toString();
} else if (sql.startsWith("@PARAMETER_META")) {
sql = sql.substring("@PARAMETER_META".length()).trim();
PreparedStatement prep = conn.prepareStatement(sql);
buff.append(getParameterResultSet(prep.getParameterMetaData()));
return buff.toString();
} else if (sql.startsWith("@META")) {
metadata = true;
sql = sql.substring("@META".length()).trim();
......@@ -1739,7 +1745,33 @@ class WebThread extends Thread implements DatabaseEventListener {
buff.append(PageParser.escapeHtml(sql));
buff.append("</td></tr>");
}
buff.append("</t>");
buff.append("</table>");
return buff.toString();
}
private String getParameterResultSet(ParameterMetaData meta) throws SQLException {
StringBuffer buff = new StringBuffer();
if (meta == null) {
return "No parameter meta data";
}
buff.append("<table cellspacing=0 cellpadding=0>");
buff.append("<tr><th>className</th><th>mode</th><th>type</th>");
buff.append("<th>typeName</th><th>precision</th><th>scale</th></tr>");
for (int i = 0; i < meta.getParameterCount(); i++) {
buff.append("</tr><td>");
buff.append(meta.getParameterClassName(i + 1));
buff.append("</td><td>");
buff.append(meta.getParameterMode(i + 1));
buff.append("</td><td>");
buff.append(meta.getParameterType(i + 1));
buff.append("</td><td>");
buff.append(meta.getParameterTypeName(i + 1));
buff.append("</td><td>");
buff.append(meta.getPrecision(i + 1));
buff.append("</td><td>");
buff.append(meta.getScale(i + 1));
buff.append("</td></tr>");
}
buff.append("</table>");
return buff.toString();
}
......
......@@ -159,8 +159,32 @@ java org.h2.test.TestAll timer
/*
out of memory problem:
drop all objects;
CREATE TABLE firsttable (id number(8) primary key, name varchar(200) not null);
CREATE TABLE secondtable (field1 number(10) not null, field2 number(8));
@LOOP 100000 insert into secondtable values(?, ?);
create index idx_number1 on secondtable(field1);
java -Xmx1024m -cp bin/h2.jar org.h2.tools.Server -log true
jdbc:h2:/home/bigjocker/workspace/mydb/mydb-h2;CACHE_SIZE=10000
The table 'secondtable' contains a little over 100.000.000 records.
disk based select distinct; order by
set max_memory_rows 10;
select distinct x from system_range(1, 200000);
set max_memory_rows 10000;
newsletter.sql
BlobTestCase2
H2BlobWriteTester
add link to new in use, links
Add google site search to web page
merge query and result frames
in-place auto-complete
......
......@@ -482,4 +482,4 @@ xmlstartdoc xmltext xor xrmd xrunhprof xsi xsm xtea xti xtime xts xvi xyz yacute
year yen yes yet yield yielding ymd you your yourkit yourself ytd yuml yusuke
yyyy zeile zero zeros zeta zip zloty zone zwj zwnj
cron ide pageview track gat analytics tracker
\ No newline at end of file
cron ide pageview track gat analytics tracker implicitly ignores
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论