提交 6c53c6e9 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add ESTIMATED_ENVELOPE system function

上级 a7e7aea5
...@@ -4736,6 +4736,23 @@ Throw an SQLException with the passed SQLState and reason. ...@@ -4736,6 +4736,23 @@ Throw an SQLException with the passed SQLState and reason.
CALL SIGNAL('23505', 'Duplicate user ID: ' || user_id); CALL SIGNAL('23505', 'Duplicate user ID: ' || user_id);
" "
"Functions (System)","ESTIMATED_ENVELOPE","
ESTIMATED_ENVELOPE(tableNameString, columnNameString)
","
Returns the estimated minimum bounding box that encloses all specified GEOMETRY values.
Only 2D coordinate plane is supported.
NULL values are ignored.
This function is only supported by MVStore engine.
Column must have a spatial index.
This function is fast, but estimation may include uncommitted data (including data from other transactions),
may return approximate bounds, or be different with actual value due to other reasons.
Use with caution.
If estimation is not available this function returns NULL.
For accurate and reliable result use ESTIMATE aggregate function instead.
","
CALL ESTIMATED_ENVELOPE('MY_TABLE', 'GEOMETRY_COLUMN');
"
"Functions (System)","FILE_READ"," "Functions (System)","FILE_READ","
FILE_READ(fileNameString [,encodingString]) FILE_READ(fileNameString [,encodingString])
"," ","
......
...@@ -27,9 +27,11 @@ import org.h2.engine.Constants; ...@@ -27,9 +27,11 @@ import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.index.Index;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mode.FunctionsMSSQLServer; import org.h2.mode.FunctionsMSSQLServer;
import org.h2.mode.FunctionsMySQL; import org.h2.mode.FunctionsMySQL;
import org.h2.mvstore.db.MVSpatialIndex;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.security.BlockCipher; import org.h2.security.BlockCipher;
...@@ -116,7 +118,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -116,7 +118,7 @@ public class Function extends Expression implements FunctionCall {
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155, IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158, READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158,
DISK_SPACE_USED = 159, SIGNAL = 160; DISK_SPACE_USED = 159, SIGNAL = 160, ESTIMATED_ENVELOPE = 161;
private static final Pattern SIGNAL_PATTERN = Pattern.compile("[0-9A-Z]{5}"); private static final Pattern SIGNAL_PATTERN = Pattern.compile("[0-9A-Z]{5}");
...@@ -456,6 +458,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -456,6 +458,7 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED, addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED,
1, Value.LONG); 1, Value.LONG);
addFunctionWithNull("SIGNAL", SIGNAL, 2, Value.NULL); addFunctionWithNull("SIGNAL", SIGNAL, 2, Value.NULL);
addFunctionNotDeterministic("ESTIMATED_ENVELOPE", ESTIMATED_ENVELOPE, 2, Value.LONG);
addFunction("H2VERSION", H2VERSION, 0, Value.STRING); addFunction("H2VERSION", H2VERSION, 0, Value.STRING);
// TableFunction // TableFunction
...@@ -883,6 +886,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -883,6 +886,9 @@ public class Function extends Expression implements FunctionCall {
case DISK_SPACE_USED: case DISK_SPACE_USED:
result = ValueLong.get(getDiskSpaceUsed(session, v0)); result = ValueLong.get(getDiskSpaceUsed(session, v0));
break; break;
case ESTIMATED_ENVELOPE:
result = getEstimatedEnvelope(session, v0, values[1]);
break;
case CAST: case CAST:
case CONVERT: { case CONVERT: {
Mode mode = database.getMode(); Mode mode = database.getMode();
...@@ -1096,11 +1102,27 @@ public class Function extends Expression implements FunctionCall { ...@@ -1096,11 +1102,27 @@ public class Function extends Expression implements FunctionCall {
return false; return false;
} }
private static long getDiskSpaceUsed(Session session, Value v0) { private static long getDiskSpaceUsed(Session session, Value tableName) {
Parser p = new Parser(session); return getTable(session, tableName).getDiskSpaceUsed();
String sql = v0.getString(); }
Table table = p.parseTableName(sql);
return table.getDiskSpaceUsed(); private static Value getEstimatedEnvelope(Session session, Value tableName, Value columnName) {
Table table = getTable(session, tableName);
Column column = table.getColumn(columnName.getString());
ArrayList<Index> indexes = table.getIndexes();
if (indexes != null) {
for (int i = 1, size = indexes.size(); i < size; i++) {
Index index = indexes.get(i);
if (index instanceof MVSpatialIndex && index.isFirstColumn(column)) {
return ((MVSpatialIndex) index).getEstimatedBounds(session);
}
}
}
return ValueNull.INSTANCE;
}
private static Table getTable(Session session, Value tableName) {
return new Parser(session).parseTableName(tableName.getString());
} }
protected static Value getNullOrValue(Session session, Expression[] args, protected static Value getNullOrValue(Session session, Expression[] args,
......
...@@ -234,6 +234,42 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -234,6 +234,42 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
return cursor.getBounds(); return cursor.getBounds();
} }
/**
* Returns the estimated minimum bounding box that encloses all keys.
*
* The returned value may be incorrect.
*
* @param session the session
* @return the estimated minimum bounding box that encloses all keys, or null
*/
public Value getEstimatedBounds(Session session) {
Page p = spatialMap.getRootPage();
int count = p.getKeyCount();
if (count > 0) {
SpatialKey key = (SpatialKey) p.getKey(0);
float bminxf = key.min(0), bmaxxf = key.max(0), bminyf = key.min(1), bmaxyf = key.max(1);
for (int i = 1; i < count; i++) {
key = (SpatialKey) p.getKey(i);
float minxf = key.min(0), maxxf = key.max(0), minyf = key.min(1), maxyf = key.max(1);
if (minxf < bminxf) {
bminxf = minxf;
}
if (maxxf > bmaxxf) {
bmaxxf = maxxf;
}
if (minyf < bminyf) {
bminyf = minyf;
}
if (maxyf > bmaxyf) {
bmaxyf = maxyf;
}
}
return ValueGeometry.getFromGeometry(new GeometryFactory().toGeometry(
new Envelope(bminxf, bmaxxf, bminyf, bmaxyf)));
}
return ValueNull.INSTANCE;
}
private SpatialKey getKey(SearchRow row) { private SpatialKey getKey(SearchRow row) {
Value v = row.getValue(columnIds[0]); Value v = row.getValue(columnIds[0]);
if (v == ValueNull.INSTANCE) { if (v == ValueNull.INSTANCE) {
......
...@@ -66,6 +66,9 @@ SELECT ENVELOPE(N) FROM (SELECT V AS N FROM TEST); ...@@ -66,6 +66,9 @@ SELECT ENVELOPE(N) FROM (SELECT V AS N FROM TEST);
SELECT ENVELOPE(V) FROM TEST; SELECT ENVELOPE(V) FROM TEST;
>> null >> null
SELECT ESTIMATED_ENVELOPE('TEST', 'V');
>> null
SELECT RAND(1000) * 0; SELECT RAND(1000) * 0;
>> 0.0 >> 0.0
...@@ -80,6 +83,10 @@ SELECT ENVELOPE(N) FROM (SELECT V AS N FROM TEST); ...@@ -80,6 +83,10 @@ SELECT ENVELOPE(N) FROM (SELECT V AS N FROM TEST);
SELECT ENVELOPE(V) FROM TEST; SELECT ENVELOPE(V) FROM TEST;
>> POLYGON ((68 78, 68 99951, 99903 99951, 99903 78, 68 78)) >> POLYGON ((68 78, 68 99951, 99903 99951, 99903 78, 68 78))
SELECT ESTIMATED_ENVELOPE('TEST', 'V');
#+mvStore#>> POLYGON ((68 78, 68 99951, 99903 99951, 99903 78, 68 78))
#-mvStore#>> null
TRUNCATE TABLE TEST; TRUNCATE TABLE TEST;
> ok > ok
......
...@@ -789,6 +789,6 @@ inconsistencies discover eliminated violates tweaks postpone leftovers ...@@ -789,6 +789,6 @@ inconsistencies discover eliminated violates tweaks postpone leftovers
tied ties tied ties
launched unavailable smallmoney erroneously multiplier newid pan streamline unmap preview unexpectedly presumably launched unavailable smallmoney erroneously multiplier newid pan streamline unmap preview unexpectedly presumably
converging smth rng curs casts unmapping unmapper converging smth rng curs casts unmapping unmapper
immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression subexpressions encloses plane immediate hhmmss scheduled hhmm prematurely postponed arranges subexpression subexpressions encloses plane caution
minxf maxxf minyf maxyf bminxf bmaxxf bminyf bmaxyf minxf maxxf minyf maxyf bminxf bmaxxf bminyf bmaxyf
minxd maxxd minyd maxyd bminxd bmaxxd bminyd bmaxyd minxd maxxd minyd maxyd bminxd bmaxxd bminyd bmaxyd
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论