Skip to content

Commit

Permalink
Merge pull request #3969 from katzyn/index_size
Browse files Browse the repository at this point in the history
Add DB_OBJECT_SIZE and DB_OBJECT_TOTAL_SIZE functions
  • Loading branch information
katzyn committed Jan 17, 2024
2 parents 3525a20 + 8f4d419 commit bbb1532
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 86 deletions.
4 changes: 4 additions & 0 deletions h2/src/docsrc/html/changelog.html
Expand Up @@ -21,6 +21,10 @@ <h1>Change Log</h1>

<h2>Next Version (unreleased)</h2>
<ul>
<li>Issue #3968: Add possibility to get index size on disk
</li>
<li>Issue #3909: Maintenance taking too much resources since 2.2.222
</li>
<li>Issue #3950: JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation
</li>
<li>PR #3947: Compound index search fix
Expand Down
15 changes: 11 additions & 4 deletions h2/src/main/org/h2/command/Parser.java
Expand Up @@ -4339,11 +4339,13 @@ private Expression readBuiltinFunctionIf(String upperName) {
return new DataTypeSQLFunction(readExpression(), readNextArgument(), readNextArgument(),
readLastArgument());
case "DB_OBJECT_ID":
return new DBObjectFunction(readExpression(), readNextArgument(), readIfArgument(),
DBObjectFunction.DB_OBJECT_ID);
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_ID);
case "DB_OBJECT_SQL":
return new DBObjectFunction(readExpression(), readNextArgument(), readIfArgument(),
DBObjectFunction.DB_OBJECT_SQL);
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_SQL);
case "DB_OBJECT_SIZE":
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_SIZE);
case "DB_OBJECT_TOTAL_SIZE":
return readDbObjectFunction(DBObjectFunction.DB_OBJECT_TOTAL_SIZE);
case "CSVWRITE":
return readParameters(new CSVWriteFunction());
case "SIGNAL":
Expand Down Expand Up @@ -4414,6 +4416,11 @@ private Expression readTrimFunction() {
return new TrimFunction(from, space, flags);
}

private Expression readDbObjectFunction(int function) {
return new DBObjectFunction(readExpression(), readNextArgument(), readIfArgument(),
function);
}

private ArrayTableFunction readUnnestFunction() {
ArrayTableFunction f = new ArrayTableFunction(ArrayTableFunction.UNNEST);
ArrayList<Column> columns = Utils.newSmallArrayList();
Expand Down
43 changes: 40 additions & 3 deletions h2/src/main/org/h2/expression/function/DBObjectFunction.java
Expand Up @@ -10,10 +10,13 @@
import org.h2.engine.SessionLocal;
import org.h2.expression.Expression;
import org.h2.expression.ExpressionVisitor;
import org.h2.index.Index;
import org.h2.message.DbException;
import org.h2.schema.Schema;
import org.h2.table.Table;
import org.h2.value.TypeInfo;
import org.h2.value.Value;
import org.h2.value.ValueBigint;
import org.h2.value.ValueInteger;
import org.h2.value.ValueNull;
import org.h2.value.ValueVarchar;
Expand All @@ -33,8 +36,18 @@ public final class DBObjectFunction extends FunctionN {
*/
public static final int DB_OBJECT_SQL = DB_OBJECT_ID + 1;

/**
* DB_OBJECT_SIZE() (non-standard).
*/
public static final int DB_OBJECT_SIZE = DB_OBJECT_SQL + 1;

/**
* DB_OBJECT_TOTAL_SIZE() (non-standard).
*/
public static final int DB_OBJECT_TOTAL_SIZE = DB_OBJECT_SIZE + 1;

private static final String[] NAMES = { //
"DB_OBJECT_ID", "DB_OBJECT_SQL" //
"DB_OBJECT_ID", "DB_OBJECT_SQL", "DB_OBJECT_SIZE", "DB_OBJECT_TOTAL_SIZE" //
};

private final int function;
Expand Down Expand Up @@ -112,9 +125,20 @@ public Value getValue(SessionLocal session, Value v1, Value v2, Value v3) {
switch (function) {
case DB_OBJECT_ID:
return ValueInteger.get(object.getId());
case DB_OBJECT_SQL:
case DB_OBJECT_SQL: {
String sql = object.getCreateSQLForMeta();
return sql != null ? ValueVarchar.get(sql, session) : ValueNull.INSTANCE;
}
case DB_OBJECT_SIZE:
case DB_OBJECT_TOTAL_SIZE: {
long size = 0L;
if (object instanceof Table) {
size = ((Table) object).getDiskSpaceUsed(function == DB_OBJECT_TOTAL_SIZE);
} else if (object instanceof Index) {
size = ((Index) object).getDiskSpaceUsed();
}
return ValueBigint.get(size);
}
default:
throw DbException.getInternalError("function=" + function);
}
Expand All @@ -123,7 +147,20 @@ public Value getValue(SessionLocal session, Value v1, Value v2, Value v3) {
@Override
public Expression optimize(SessionLocal session) {
optimizeArguments(session, false);
type = function == DB_OBJECT_ID ? TypeInfo.TYPE_INTEGER : TypeInfo.TYPE_VARCHAR;
switch (function) {
case DB_OBJECT_ID:
type = TypeInfo.TYPE_INTEGER;
break;
case DB_OBJECT_SQL:
type = TypeInfo.TYPE_VARCHAR;
break;
case DB_OBJECT_SIZE:
case DB_OBJECT_TOTAL_SIZE:
type = TypeInfo.TYPE_BIGINT;
break;
default:
throw DbException.getInternalError("function=" + function);
}
return this;
}

Expand Down
Expand Up @@ -52,7 +52,7 @@ public Value getValue(SessionLocal session, Value v1, Value v2) {
Table table = new Parser(session).parseTableName(v1.getString());
l: switch (function) {
case DISK_SPACE_USED:
v1 = ValueBigint.get(table.getDiskSpaceUsed());
v1 = ValueBigint.get(table.getDiskSpaceUsed(false));
break;
case ESTIMATED_ENVELOPE: {
Column column = table.getColumn(v2.getString());
Expand Down
13 changes: 8 additions & 5 deletions h2/src/main/org/h2/index/IndexCondition.java
Expand Up @@ -88,7 +88,7 @@ public class IndexCondition {
* {@link Comparison}
*/
private IndexCondition(int compareType, ExpressionColumn column, Column[] columns, Expression expression,
List<Expression> list, Query query) {
List<Expression> list, Query query) {

this.compareType = compareType;
if (column != null) {
Expand Down Expand Up @@ -510,10 +510,13 @@ public boolean isEvaluatable() {
}

/**
* Creates a copy of this index condition but using the {@link Index#getIndexColumns() columns} of the {@code index}.
* @param index a non-null Index
* @return a new IndexCondition with the specified columns, or {@code null} if the index does not match with this
* condition.
* Creates a copy of this index condition but using the
* {@link Index#getIndexColumns() columns} of the {@code index}.
*
* @param index
* a non-null Index
* @return a new IndexCondition with the specified columns, or {@code null}
* if the index does not match with this condition.
*/
public IndexCondition cloneWithIndexColumns(Index index) {
if (!isCompoundColumns()) {
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/index/MetaIndex.java
Expand Up @@ -118,7 +118,7 @@ public long getRowCountApproximation(SessionLocal session) {

@Override
public long getDiskSpaceUsed() {
return meta.getDiskSpaceUsed();
return meta.getDiskSpaceUsed(false);
}

@Override
Expand Down
21 changes: 15 additions & 6 deletions h2/src/main/org/h2/mode/FunctionsPostgreSQL.java
Expand Up @@ -70,7 +70,9 @@ public final class FunctionsPostgreSQL extends ModeFunction {

private static final int PG_RELATION_SIZE = PG_POSTMASTER_START_TIME + 1;

private static final int PG_TABLE_IS_VISIBLE = PG_RELATION_SIZE + 1;
private static final int PG_TOTAL_RELATION_SIZE = PG_RELATION_SIZE + 1;

private static final int PG_TABLE_IS_VISIBLE = PG_TOTAL_RELATION_SIZE + 1;

private static final int SET_CONFIG = PG_TABLE_IS_VISIBLE + 1;

Expand Down Expand Up @@ -114,6 +116,8 @@ public final class FunctionsPostgreSQL extends ModeFunction {
false));
FUNCTIONS.put("PG_RELATION_SIZE",
new FunctionInfo("PG_RELATION_SIZE", PG_RELATION_SIZE, VAR_ARGS, Value.BIGINT, true, false));
FUNCTIONS.put("PG_TOTAL_RELATION_SIZE", new FunctionInfo("PG_TOTAL_RELATION_SIZE", PG_TOTAL_RELATION_SIZE,
VAR_ARGS, Value.BIGINT, true, false));
FUNCTIONS.put("PG_TABLE_IS_VISIBLE",
new FunctionInfo("PG_TABLE_IS_VISIBLE", PG_TABLE_IS_VISIBLE, 1, Value.BOOLEAN, true, false));
FUNCTIONS.put("SET_CONFIG", new FunctionInfo("SET_CONFIG", SET_CONFIG, 3, Value.VARCHAR, true, false));
Expand Down Expand Up @@ -159,6 +163,7 @@ protected void checkParameterCount(int len) {
break;
case OBJ_DESCRIPTION:
case PG_RELATION_SIZE:
case PG_TOTAL_RELATION_SIZE:
min = 1;
max = 2;
break;
Expand Down Expand Up @@ -257,7 +262,11 @@ public Value getValue(SessionLocal session) {
break;
case PG_RELATION_SIZE:
// Optional second argument is ignored
result = relationSize(session, v0);
result = relationSize(session, v0, false);
break;
case PG_TOTAL_RELATION_SIZE:
// Optional second argument is ignored
result = relationSize(session, v0, true);
break;
case SET_CONFIG:
// Not implemented
Expand Down Expand Up @@ -361,23 +370,23 @@ private static String getUserbyid(SessionLocal session, int uid) {
return name;
}

private static Value relationSize(SessionLocal session, Value tableOidOrName) {
private static Value relationSize(SessionLocal session, Value tableOidOrName, boolean total) {
Table t;
if (tableOidOrName.getValueType() == Value.INTEGER) {
l: if (tableOidOrName.getValueType() == Value.INTEGER) {
int tid = tableOidOrName.getInt();
for (Schema schema : session.getDatabase().getAllSchemasNoMeta()) {
for (Table table : schema.getAllTablesAndViews(session)) {
if (tid == table.getId()) {
t = table;
break;
break l;
}
}
}
return ValueNull.INSTANCE;
} else {
t = new Parser(session).parseTableName(tableOidOrName.getString());
}
return ValueBigint.get(t.getDiskSpaceUsed());
return ValueBigint.get(t.getDiskSpaceUsed(total));
}

}
5 changes: 5 additions & 0 deletions h2/src/main/org/h2/mvstore/db/MVIndex.java
Expand Up @@ -44,4 +44,9 @@ protected MVIndex(Table newTable, int id, String name, IndexColumn[] newIndexCol

public abstract MVMap<K,VersionedValue<V>> getMVMap();

@Override
public long getDiskSpaceUsed() {
return getMVMap().getRootPage().getDiskSpaceUsed();
}

}
5 changes: 0 additions & 5 deletions h2/src/main/org/h2/mvstore/db/MVPrimaryIndex.java
Expand Up @@ -346,11 +346,6 @@ public long getRowCountApproximation(SessionLocal session) {
return getRowCountMax();
}

@Override
public long getDiskSpaceUsed() {
return dataMap.map.getRootPage().getDiskSpaceUsed();
}

public String getMapName() {
return mapName;
}
Expand Down
6 changes: 0 additions & 6 deletions h2/src/main/org/h2/mvstore/db/MVSecondaryIndex.java
Expand Up @@ -361,12 +361,6 @@ public long getRowCountApproximation(SessionLocal session) {
}
}

@Override
public long getDiskSpaceUsed() {
// TODO estimate disk space usage
return 0;
}

@Override
public boolean canFindNext() {
return true;
Expand Down
7 changes: 0 additions & 7 deletions h2/src/main/org/h2/mvstore/db/MVSpatialIndex.java
Expand Up @@ -335,12 +335,6 @@ public long getRowCountApproximation(SessionLocal session) {
}
}

@Override
public long getDiskSpaceUsed() {
// TODO estimate disk space usage
return 0;
}

/**
* Get the map to store the data.
*
Expand All @@ -360,7 +354,6 @@ public MVMap<Spatial, VersionedValue<Value>> getMVMap() {
return dataMap.map;
}


/**
* A cursor.
*/
Expand Down
14 changes: 12 additions & 2 deletions h2/src/main/org/h2/mvstore/db/MVTable.java
Expand Up @@ -623,8 +623,18 @@ public long getRowCountApproximation(SessionLocal session) {
}

@Override
public long getDiskSpaceUsed() {
return primaryIndex.getDiskSpaceUsed();
public long getDiskSpaceUsed(boolean total) {
if (total) {
long size = 0L;
for (Index index : getIndexes()) {
if (!(index instanceof MVDelegateIndex)) {
size += index.getDiskSpaceUsed();
}
}
return size;
} else {
return primaryIndex.getDiskSpaceUsed();
}
}

/**
Expand Down
24 changes: 23 additions & 1 deletion h2/src/main/org/h2/res/help.csv
Expand Up @@ -6495,6 +6495,26 @@ CALL DB_OBJECT_SQL('ROLE', 'MANAGER');
CALL DB_OBJECT_SQL('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DB_OBJECT_SIZE","
@h2@ DB_OBJECT_SIZE({'INDEX'|'TABLE'}, schemaNameString, objectNameString)
","
Returns the approximate amount of space used by the specified table (excluding its indexes) or index.
Size of large LOBs currently is not included into estimation.
This function may be expensive since it has to load every page in the table or index.
","
CALL DB_OBJECT_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DB_OBJECT_TOTAL_SIZE","
@h2@ DB_OBJECT_TOTAL_SIZE('TABLE', schemaNameString, objectNameString)
","
Returns the approximate amount of space used by the specified table and all its indexes.
Size of large LOBs currently is not included into estimation.
This function may be expensive since it has to load every page in the table and its indexes.
","
CALL DB_OBJECT_TOTAL_SIZE('TABLE', 'PUBLIC', 'MY_TABLE');
"

"Functions (System)","DECODE","
@c@ DECODE(value, whenValue, thenValue [,...])
","
Expand All @@ -6507,11 +6527,13 @@ CALL DECODE(RAND()>0.5, 0, 'Red', 1, 'Black');
"

"Functions (System)","DISK_SPACE_USED","
@h2@ DISK_SPACE_USED(tableNameString)
@c@ DISK_SPACE_USED(tableNameString)
","
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.
This function is deprecated,
use [DB_OBJECT_SIZE](https://h2database.com/html/functions.html#db_object_size) instead of it.
","
CALL DISK_SPACE_USED('my_table');
"
Expand Down
12 changes: 8 additions & 4 deletions h2/src/main/org/h2/table/Column.java
Expand Up @@ -193,11 +193,15 @@ public Value convert(CastDataProvider provider, Value v) {

/**
* Converts the values in a ValueRow based on the passed column info.
* Creates a new instance if any of the contained item must be converted. Otherwise, returns the same {@code valueRow}.
* Creates a new instance if any of the contained item must be converted.
* Otherwise, returns the same {@code valueRow}.
*
* @param provider the cast information provider
* @param columns the column info list used for the conversation
* @param valueRow the holder of the values
* @param provider
* the cast information provider
* @param columns
* the column info list used for the conversation
* @param valueRow
* the holder of the values
* @return a ValueRow which contains the converted values
*
* @see Column#convert(CastDataProvider, Value)
Expand Down
2 changes: 1 addition & 1 deletion h2/src/main/org/h2/table/Table.java
Expand Up @@ -395,7 +395,7 @@ public boolean canReference() {
*/
public abstract long getRowCountApproximation(SessionLocal session);

public long getDiskSpaceUsed() {
public long getDiskSpaceUsed(boolean total) {
return 0L;
}

Expand Down
3 changes: 2 additions & 1 deletion h2/src/test/org/h2/test/db/TestCompatibility.java
Expand Up @@ -405,7 +405,8 @@ private void testMySQL() throws SQLException {
stat.execute("CREATE TABLE TEST_5" +
"(ID INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDb auto_increment=3 default charset=UTF8");
stat.execute("CREATE TABLE TEST_6" +
"(ID INT AUTO_INCREMENT PRIMARY KEY) ENGINE=MyISAM default character set UTF8MB4, auto_increment 3");
"(ID INT AUTO_INCREMENT PRIMARY KEY) " +
"ENGINE=MyISAM default character set UTF8MB4, auto_increment 3");
stat.execute("CREATE TABLE TEST_7" +
"(ID INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDb auto_increment=3 charset=UTF8 comment 'text'");
stat.execute("CREATE TABLE TEST_8" +
Expand Down

0 comments on commit bbb1532

Please sign in to comment.