-
Notifications
You must be signed in to change notification settings - Fork 5
Description
The format for a MultiPoint is being written using the compressed format when it's saved to the database. Take this code for example:
var c = new OracleConnection("my_cs");
c.Open();
var s = "INSERT INTO MY_TABLE(GEO_DATA) VALUES (:p_name)";
// Multi point with 2 POINTS
var mp = new MultiPoint([new Point(1, 1), new Point(2, 2)]);
var ogw = new OracleGeometryWriter();
SdoGeometry sdoGeometry = ogw.Write(mp);
sdoGeometry.Sdo_Srid = 1;
// Parameter
var param = new OracleParameter();
param.ParameterName = "p_name";
param.DbType = DbType.Object;
param.Direction = ParameterDirection.Input;
param.UdtTypeName = "MDSYS.SDO_GEOMETRY";
param.Value = sdoGeometry;
var com = new OracleCommand(s, c);
com.Parameters.Add(param);
com.ExecuteNonQuery();
This code DOES create a MultiPoint in the compressed format. If you were to run the following SQL on the resulting value:
SELECT
(SDO_UTIL.GETNUMELEM(GEO_DATA)) NUM_GEOMETRIES,
FROM MY_TABLE
It will return 1, no matter how many points are added into the MultiPoint, in this case it should be 2 (at least if you are following OGC). You can see this by looking at how the ElemArray and OrdinatesArray come back from the call to Write:
| ElemArray | {double[3]} | double[]
| [0] | 1 | double
| [1] | 1 | double
| [2] | 2 | double
| OrdinatesArray | {double[4]} | double[]
| [0] | 1 | double
| [1] | 1 | double
| [2] | 2 | double
| [3] | 2 | double
Here's how they should look
| ElemArray | {double[6]} | double[]
| [0] | 1 | double
| [1] | 1 | double
| [2] | 1 | double
| [3] | 3 | double
| [4] | 1 | double
| [5] | 1 | double
| OrdinatesArray | {double[4]} | double[]
| [0] | 1 | double
| [1] | 1 | double
| [2] | 2 | double
| [3] | 2 | double
When formatted like this (expanded format) the above call to SDO_UTIL.GETNUMELEM will return the correct number.
Rewriting ProcessMultiPoint in OracleGeometryWriter to
private int ProcessMultiPoint(MultiPoint multiPoint, List<double> elemInfoList, List<double> ordinateList, int pos)
{
int cnt = multiPoint.NumGeometries;
for (int i = 0; i < cnt; i++)
{
var point = (Point)multiPoint.GetGeometryN(i);
elemInfoList.Add(pos);
elemInfoList.Add((int)SdoEType.Coordinate);
elemInfoList.Add(1);
ordinateList.Add(point.X);
ordinateList.Add(point.Y);
pos += 2;
}
return pos;
}
Switches it to a more compatible format. Oracle does support both a compressed and an expanded format for MultiPoints and the code as written currently uses the compressed format. However, a quirk of Oracle is that the SDO_UTIL.GETNUMELEM function returns different values depending on the format used. As such it would be better to support the standard format that returns the standard results one would expect from ST_NumGeometries or at least make it configurable.