提交 18808fa8 authored 作者: noelgrandin's avatar noelgrandin

Add a DISK_SPACE_USED system function. Fixes issue 270.

上级 cf7ee9c5
......@@ -3573,6 +3573,16 @@ This function is provided for Oracle compatibility (see there for details).
CALL DECODE(RAND()>0.5, 0, 'Red', 1, 'Black');
"
"Functions (System)","DISK_SPACE_USED","
DISK_SPACE_USED(tablename)
","
Returns the approximate amount of space used by the table specified.
Does not currently take into account indexes or LOB's.
This function may be expensive since it has to load every page in the table.
","
CALL DISK_SPACE_USED('my_table');
"
"Functions (System)","FILE_READ","
FILE_READ(fileNameString [,encodingString])
","
......
......@@ -36,6 +36,7 @@ Change Log
</ul><li>Support ALTER TABLE ADD ... AFTER. Patch from Andrew Gaul (argaul at gmail.com). Fixes issue 401.
</ul><li>support "SELECT version()". Patch from Andrew Gaul. Fixes issue 406.
</ul><li>Improved OSGi support. H2 now registers itself as a DataSourceFactory service. Fixes issue 365.
</ul><li>Add a DISK_SPACE_USED system function. Fixes issue 270.
</li></ul>
<h2>Version 1.3.170 (2012-11-30)</h2>
......
......@@ -5379,4 +5379,16 @@ public class Parser {
return readExpression();
}
/**
* Parse a SQL code snippet that represents a table name.
*
* @param sql the code snippet
* @return the table object
*/
public Table parseTableName(String sql) {
parameters = New.arrayList();
initialize(sql);
read();
return readTableOrView();
}
}
......@@ -40,6 +40,7 @@ import org.h2.store.fs.FileUtils;
import org.h2.table.Column;
import org.h2.table.ColumnResolver;
import org.h2.table.LinkSchema;
import org.h2.table.Table;
import org.h2.table.TableFilter;
import org.h2.tools.CompressTool;
import org.h2.tools.Csv;
......@@ -92,7 +93,7 @@ public class Function extends Expression implements FunctionCall {
ISO_YEAR = 123, ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125;
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, IDENTITY = 153, SCOPE_IDENTITY = 154,
AUTOCOMMIT = 155, READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158;
AUTOCOMMIT = 155, READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158, DISK_SPACE_USED = 159;
public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, COALESCE = 204, NULLIF = 205,
CASE = 206, NEXTVAL = 207, CURRVAL = 208, ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211,
......@@ -346,6 +347,7 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING);
addFunctionWithNull("DECODE", DECODE, VAR_ARGS, Value.NULL);
addFunction("VERSION", VERSION, 0, Value.STRING);
addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED, 1, Value.LONG);
// TableFunction
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
......@@ -760,6 +762,9 @@ public class Function extends Expression implements FunctionCall {
case LOCK_TIMEOUT:
result = ValueInt.get(session.getLockTimeout());
break;
case DISK_SPACE_USED:
result = ValueLong.get(getDiskSpaceUsed(session, v0));
break;
case CAST:
case CONVERT: {
v0 = v0.convertTo(dataType);
......@@ -942,6 +947,13 @@ public class Function extends Expression implements FunctionCall {
return false;
}
private static long getDiskSpaceUsed(Session session, Value v0) {
Parser p = new Parser(session);
String sql = v0.getString();
Table table = p.parseTableName(sql);
return table.getDiskSpaceUsed();
}
private static Value getNullOrValue(Session session, Expression[] args, Value[] values, int i) {
if (i >= args.length) {
return null;
......
......@@ -90,6 +90,10 @@ public class FunctionIndex extends BaseIndex {
return functionTable.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return 0;
}
public String getPlanSQL() {
return "function";
}
......
......@@ -81,6 +81,10 @@ public class HashIndex extends BaseIndex {
return rows.size();
}
public long getDiskSpaceUsed() {
return 0;
}
public void close(Session session) {
// nothing to do
}
......
......@@ -156,6 +156,11 @@ public interface Index extends SchemaObject {
*/
long getRowCountApproximation();
/**
* @return the estimated number of bytes of disk space used by this page and all child pages.
*/
long getDiskSpaceUsed();
/**
* Compare two rows.
*
......
......@@ -246,4 +246,7 @@ public class LinkedIndex extends BaseIndex {
return rowCount;
}
public long getDiskSpaceUsed() {
return 0;
}
}
......@@ -97,6 +97,10 @@ public class MetaIndex extends BaseIndex {
return MetaTable.ROW_COUNT_APPROXIMATION;
}
public long getDiskSpaceUsed() {
return meta.getDiskSpaceUsed();
}
public String getPlanSQL() {
return "meta";
}
......
......@@ -302,6 +302,10 @@ public class MultiVersionIndex implements Index {
return base.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return base.getDiskSpaceUsed();
}
public Index getBaseIndex() {
return base;
}
......
......@@ -300,6 +300,10 @@ public class PageBtreeIndex extends PageIndex {
return tableData.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return tableData.getDiskSpaceUsed();
}
public long getRowCount(Session session) {
return rowCount;
}
......
......@@ -88,6 +88,11 @@ abstract class PageData extends Page {
*/
abstract void setRowCountStored(int rowCount);
/**
* @return the estimated number of bytes of disk space used by this page and all child pages.
*/
abstract long getDiskSpaceUsed();
/**
* Find an entry by key.
*
......
......@@ -427,6 +427,11 @@ public class PageDataIndex extends PageIndex {
return rowCount;
}
public long getDiskSpaceUsed() {
PageData root = getPage(rootPageId, 0);
return root.getDiskSpaceUsed();
}
public String getCreateSQL() {
return null;
}
......
......@@ -451,6 +451,10 @@ public class PageDataLeaf extends PageData {
// ignore
}
long getDiskSpaceUsed() {
return index.getPageStore().getPageSize();
}
public void write() {
writeData();
index.getPageStore().writePage(getPos(), data);
......
......@@ -277,7 +277,7 @@ public class PageDataNode extends PageData {
int child = childPageIds[i];
PageData page = index.getPage(child, getPos());
if (getPos() == page.getPos()) {
throw DbException.throwInternalError("Page it its own child: " + getPos());
throw DbException.throwInternalError("Page is its own child: " + getPos());
}
count += page.getRowCount();
index.getDatabase().setProgress(DatabaseEventListener.STATE_SCAN_FILE,
......@@ -288,6 +288,21 @@ public class PageDataNode extends PageData {
return rowCount;
}
long getDiskSpaceUsed() {
long count = 0;
for (int i = 0; i < entryCount + 1; i++) {
int child = childPageIds[i];
PageData page = index.getPage(child, getPos());
if (getPos() == page.getPos()) {
throw DbException.throwInternalError("Page is its own child: " + getPos());
}
count += page.getDiskSpaceUsed();
index.getDatabase().setProgress(DatabaseEventListener.STATE_SCAN_FILE,
index.getTable() + "." + index.getName(), (int) (count>>16), Integer.MAX_VALUE);
}
return count;
}
void setRowCountStored(int rowCount) {
this.rowCount = rowCount;
if (rowCountStored != rowCount) {
......
......@@ -117,6 +117,10 @@ public class PageDelegateIndex extends PageIndex {
return mainIndex.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return mainIndex.getDiskSpaceUsed();
}
public void writeRowCount() {
// ignore
}
......
......@@ -95,4 +95,7 @@ public class RangeIndex extends BaseIndex {
return rangeTable.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return 0;
}
}
......@@ -232,6 +232,10 @@ public class ScanIndex extends BaseIndex {
return rowCount;
}
public long getDiskSpaceUsed() {
return 0;
}
public String getPlanSQL() {
return table.getSQL() + ".tableScan";
}
......
......@@ -383,4 +383,8 @@ public class TreeIndex extends BaseIndex {
return rowCount;
}
public long getDiskSpaceUsed() {
return 0;
}
}
......@@ -375,6 +375,10 @@ public class ViewIndex extends BaseIndex {
return 0;
}
public long getDiskSpaceUsed() {
return 0;
}
public boolean isRecursive() {
return recursive;
}
......
......@@ -118,4 +118,8 @@ public class MVDelegateIndex extends BaseIndex {
return mainIndex.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return 0;
}
}
......@@ -187,6 +187,10 @@ public class MVPrimaryIndex extends BaseIndex {
return map.getSize();
}
public long getDiskSpaceUsed() {
return 0; // TODO
}
@Override
public void checkRename() {
// ok
......
......@@ -150,6 +150,10 @@ public class MVSecondaryIndex extends BaseIndex {
return map.getSize();
}
public long getDiskSpaceUsed() {
return 0; // TODO
}
@Override
public void checkRename() {
// ok
......
......@@ -418,6 +418,10 @@ public class MVTable extends TableBase {
return primaryIndex.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return primaryIndex.getDiskSpaceUsed();
}
@Override
public void checkRename() {
// ok
......
......@@ -217,6 +217,10 @@ public class FunctionTable extends Table {
return rowCount;
}
public long getDiskSpaceUsed() {
return 0;
}
public boolean isDeterministic() {
return function.isDeterministic();
}
......
......@@ -1801,6 +1801,10 @@ public class MetaTable extends Table {
return ROW_COUNT_APPROXIMATION;
}
public long getDiskSpaceUsed() {
return 0;
}
public boolean isDeterministic() {
return true;
}
......
......@@ -167,6 +167,10 @@ public class RangeTable extends Table {
return 100;
}
public long getDiskSpaceUsed() {
return 0;
}
public boolean isDeterministic() {
return true;
}
......
......@@ -725,6 +725,11 @@ public class RegularTable extends TableBase {
return scanIndex.getRowCountApproximation();
}
@Override
public long getDiskSpaceUsed() {
return scanIndex.getDiskSpaceUsed();
}
public void setCompareMode(CompareMode compareMode) {
this.compareMode = compareMode;
}
......
......@@ -293,6 +293,8 @@ public abstract class Table extends SchemaObjectBase {
*/
public abstract long getRowCountApproximation();
public abstract long getDiskSpaceUsed();
/**
* Get the row id column if this table has one.
*
......
......@@ -598,6 +598,10 @@ public class TableLink extends Table {
return ROW_COUNT_APPROXIMATION;
}
public long getDiskSpaceUsed() {
return 0;
}
/**
* Add this prepared statement to the list of cached statements.
*
......
......@@ -437,6 +437,10 @@ public class TableView extends Table {
return ROW_COUNT_APPROXIMATION;
}
public long getDiskSpaceUsed() {
return 0;
}
public int getParameterOffset() {
return topQuery == null ? 0 : topQuery.getParameters().size();
}
......
......@@ -148,6 +148,10 @@ public class TestTableEngines extends TestBase {
return table.getRowCountApproximation();
}
public long getDiskSpaceUsed() {
return table.getDiskSpaceUsed();
}
public long getRowCount(Session session) {
return table.getRowCount(session);
}
......@@ -257,6 +261,10 @@ public class TestTableEngines extends TestBase {
return row == null ? 0 : 1;
}
public long getDiskSpaceUsed() {
return 0;
}
@Override
public Index getScanIndex(Session session) {
return scanIndex;
......
......@@ -9972,3 +9972,13 @@ select * from word;
drop table word;
> ok
create table test(id int, name varchar);
> ok
insert into test values(5, 'b'), (5, 'b'), (20, 'a');
> update count: 3
CALL DISK_SPACE_USED('test');
> DISK_SPACE_USED('test')
> -----------------------
> 2048
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论