提交 fe593d24 authored 作者: Thomas Mueller's avatar Thomas Mueller

Geometry: the returned geometry object is copied when needed.

上级 a268defe
...@@ -24,7 +24,7 @@ Change Log ...@@ -24,7 +24,7 @@ Change Log
</li><li>Column constraints are also visible in views (patch from Nicolas Fortin for H2GIS). </li><li>Column constraints are also visible in views (patch from Nicolas Fortin for H2GIS).
</li><li>Granting a additional right to a role that already had a right for that table was not working. </li><li>Granting a additional right to a role that already had a right for that table was not working.
</li><li>Spatial index: a few bugs have been fixed (using spatial constraints in views, </li><li>Spatial index: a few bugs have been fixed (using spatial constraints in views,
transferring geometry objects over TCP/IP). transferring geometry objects over TCP/IP, the returned geometry object is copied when needed).
</li><li>Issue 551: the datatype documentation was incorrect (found by Bernd Eckenfels). </li><li>Issue 551: the datatype documentation was incorrect (found by Bernd Eckenfels).
</li><li>Issue 368: ON DUPLICATE KEY UPDATE did not work for multi-row inserts. </li><li>Issue 368: ON DUPLICATE KEY UPDATE did not work for multi-row inserts.
Test case from Angus Macdonald. Test case from Angus Macdonald.
......
...@@ -131,7 +131,7 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -131,7 +131,7 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
private SpatialKey getEnvelope(SearchRow row) { private SpatialKey getEnvelope(SearchRow row) {
Value v = row.getValue(columnIds[0]); Value v = row.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry(); Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal(); Envelope env = g.getEnvelopeInternal();
return new SpatialKey(row.getKey(), return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(), (float) env.getMinX(), (float) env.getMaxX(),
......
...@@ -168,7 +168,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -168,7 +168,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
return null; return null;
} }
Value v = r.getValue(columnIds[0]); Value v = r.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry(); Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal(); Envelope env = g.getEnvelopeInternal();
return new SpatialKey(r.getKey(), return new SpatialKey(r.getKey(),
(float) env.getMinX(), (float) env.getMaxX(), (float) env.getMinX(), (float) env.getMaxX(),
...@@ -222,7 +222,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -222,7 +222,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
private SpatialKey getEnvelope(SearchRow row) { private SpatialKey getEnvelope(SearchRow row) {
Value v = row.getValue(columnIds[0]); Value v = row.getValue(columnIds[0]);
Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometry(); Geometry g = ((ValueGeometry) v.convertTo(Value.GEOMETRY)).getGeometryNoCopy();
Envelope env = g.getEnvelopeInternal(); Envelope env = g.getEnvelopeInternal();
return new SpatialKey(row.getKey(), return new SpatialKey(row.getKey(),
(float) env.getMinX(), (float) env.getMaxX(), (float) env.getMinX(), (float) env.getMaxX(),
......
...@@ -12,6 +12,7 @@ import java.util.Arrays; ...@@ -12,6 +12,7 @@ import java.util.Arrays;
import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceFilter; import com.vividsolutions.jts.geom.CoordinateSequenceFilter;
import com.vividsolutions.jts.geom.PrecisionModel;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Envelope;
...@@ -106,6 +107,22 @@ public class ValueGeometry extends Value { ...@@ -106,6 +107,22 @@ public class ValueGeometry extends Value {
} }
} }
/**
* Get or create a geometry value for the given geometry.
*
* @param s the WKT representation of the geometry
* @return the value
*/
public static ValueGeometry get(String s, int srid) {
try {
GeometryFactory geometryFactory = new GeometryFactory(new PrecisionModel(), srid);
Geometry g = new WKTReader(geometryFactory).read(s);
return get(g);
} catch (ParseException ex) {
throw DbException.convert(ex);
}
}
/** /**
* Get or create a geometry value for the given geometry. * Get or create a geometry value for the given geometry.
* *
...@@ -116,7 +133,17 @@ public class ValueGeometry extends Value { ...@@ -116,7 +133,17 @@ public class ValueGeometry extends Value {
return (ValueGeometry) Value.cache(new ValueGeometry(bytes, null)); return (ValueGeometry) Value.cache(new ValueGeometry(bytes, null));
} }
/**
* Get a copy of geometry object. Geometry object is mutable. The returned
* object is therefore copied before returning.
*
* @return a copy of the geometry object
*/
public Geometry getGeometry() { public Geometry getGeometry() {
return (Geometry) getGeometryNoCopy().clone();
}
public Geometry getGeometryNoCopy() {
if (geometry == null) { if (geometry == null) {
try { try {
geometry = new WKBReader().read(bytes); geometry = new WKBReader().read(bytes);
...@@ -136,8 +163,8 @@ public class ValueGeometry extends Value { ...@@ -136,8 +163,8 @@ public class ValueGeometry extends Value {
*/ */
public boolean intersectsBoundingBox(ValueGeometry r) { public boolean intersectsBoundingBox(ValueGeometry r) {
// the Geometry object caches the envelope // the Geometry object caches the envelope
return getGeometry().getEnvelopeInternal().intersects( return getGeometryNoCopy().getEnvelopeInternal().intersects(
r.getGeometry().getEnvelopeInternal()); r.getGeometryNoCopy().getEnvelopeInternal());
} }
/** /**
...@@ -148,8 +175,8 @@ public class ValueGeometry extends Value { ...@@ -148,8 +175,8 @@ public class ValueGeometry extends Value {
*/ */
public Value getEnvelopeUnion(ValueGeometry r) { public Value getEnvelopeUnion(ValueGeometry r) {
GeometryFactory gf = new GeometryFactory(); GeometryFactory gf = new GeometryFactory();
Envelope mergedEnvelope = new Envelope(getGeometry().getEnvelopeInternal()); Envelope mergedEnvelope = new Envelope(getGeometryNoCopy().getEnvelopeInternal());
mergedEnvelope.expandToInclude(r.getGeometry().getEnvelopeInternal()); mergedEnvelope.expandToInclude(r.getGeometryNoCopy().getEnvelopeInternal());
return get(gf.toGeometry(mergedEnvelope)); return get(gf.toGeometry(mergedEnvelope));
} }
...@@ -160,8 +187,8 @@ public class ValueGeometry extends Value { ...@@ -160,8 +187,8 @@ public class ValueGeometry extends Value {
* @return the intersection of this geometry envelope and another * @return the intersection of this geometry envelope and another
*/ */
public ValueGeometry getEnvelopeIntersection(ValueGeometry r) { public ValueGeometry getEnvelopeIntersection(ValueGeometry r) {
Envelope e1 = getGeometry().getEnvelopeInternal(); Envelope e1 = getGeometryNoCopy().getEnvelopeInternal();
Envelope e2 = r.getGeometry().getEnvelopeInternal(); Envelope e2 = r.getGeometryNoCopy().getEnvelopeInternal();
Envelope e3 = e1.intersection(e2); Envelope e3 = e1.intersection(e2);
// try to re-use the object // try to re-use the object
if (e3 == e1) { if (e3 == e1) {
...@@ -188,8 +215,8 @@ public class ValueGeometry extends Value { ...@@ -188,8 +215,8 @@ public class ValueGeometry extends Value {
@Override @Override
protected int compareSecure(Value v, CompareMode mode) { protected int compareSecure(Value v, CompareMode mode) {
Geometry g = ((ValueGeometry) v).getGeometry(); Geometry g = ((ValueGeometry) v).getGeometryNoCopy();
return getGeometry().compareTo(g); return getGeometryNoCopy().compareTo(g);
} }
@Override @Override
...@@ -225,7 +252,7 @@ public class ValueGeometry extends Value { ...@@ -225,7 +252,7 @@ public class ValueGeometry extends Value {
@Override @Override
public void set(PreparedStatement prep, int parameterIndex) public void set(PreparedStatement prep, int parameterIndex)
throws SQLException { throws SQLException {
prep.setObject(parameterIndex, getGeometry()); prep.setObject(parameterIndex, getGeometryNoCopy());
} }
@Override @Override
...@@ -252,7 +279,7 @@ public class ValueGeometry extends Value { ...@@ -252,7 +279,7 @@ public class ValueGeometry extends Value {
* @return the well-known-text * @return the well-known-text
*/ */
public String getWKT() { public String getWKT() {
return new WKTWriter().write(getGeometry()); return new WKTWriter().write(getGeometryNoCopy());
} }
/** /**
......
...@@ -15,6 +15,8 @@ import java.sql.Types; ...@@ -15,6 +15,8 @@ import java.sql.Types;
import java.util.Random; import java.util.Random;
import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.util.AffineTransformation;
import org.h2.api.Aggregate; import org.h2.api.Aggregate;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
...@@ -84,6 +86,7 @@ public class TestSpatial extends TestBase { ...@@ -84,6 +86,7 @@ public class TestSpatial extends TestBase {
testAggregateWithGeometry(); testAggregateWithGeometry();
testTableViewSpatialPredicate(); testTableViewSpatialPredicate();
testValueGeometryScript(); testValueGeometryScript();
testInPlaceUpdate();
} }
private void testHashCode() { private void testHashCode() {
...@@ -582,13 +585,12 @@ public class TestSpatial extends TestBase { ...@@ -582,13 +585,12 @@ public class TestSpatial extends TestBase {
*/ */
private void testWKB() { private void testWKB() {
ValueGeometry geom3d = ValueGeometry.get( ValueGeometry geom3d = ValueGeometry.get(
"POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))"); "POLYGON ((67 13 6, 67 18 5, 59 18 4, 59 13 6, 67 13 6))", 27572);
ValueGeometry copy = ValueGeometry.get(geom3d.getBytes()); ValueGeometry copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(6, copy.getGeometry().getCoordinates()[0].z); assertEquals(6, copy.getGeometry().getCoordinates()[0].z);
assertEquals(5, copy.getGeometry().getCoordinates()[1].z); assertEquals(5, copy.getGeometry().getCoordinates()[1].z);
assertEquals(4, copy.getGeometry().getCoordinates()[2].z); assertEquals(4, copy.getGeometry().getCoordinates()[2].z);
// Test SRID // Test SRID
geom3d.getGeometry().setSRID(27572);
copy = ValueGeometry.get(geom3d.getBytes()); copy = ValueGeometry.get(geom3d.getBytes());
assertEquals(27572, copy.getGeometry().getSRID()); assertEquals(27572, copy.getGeometry().getSRID());
} }
...@@ -802,4 +804,30 @@ public class TestSpatial extends TestBase { ...@@ -802,4 +804,30 @@ public class TestSpatial extends TestBase {
conn.close(); conn.close();
} }
} }
/**
* If the user mutate the geometry of the object, the object cache must not
* be updated.
*/
private void testInPlaceUpdate() throws SQLException {
Connection conn = getConnection(url);
try {
ResultSet rs = conn.createStatement().executeQuery(
"SELECT 'POINT(1 1)'::geometry");
assertTrue(rs.next());
// Mutate the geometry
((Geometry) rs.getObject(1)).apply(new AffineTransformation(1, 0,
1, 1, 0, 1));
rs.close();
rs = conn.createStatement().executeQuery(
"SELECT 'POINT(1 1)'::geometry");
assertTrue(rs.next());
// Check if the geometry is the one requested
assertEquals(1, ((Point) rs.getObject(1)).getX());
assertEquals(1, ((Point) rs.getObject(1)).getY());
rs.close();
} finally {
conn.close();
}
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论