Top 5 Recent Articles
ARTICLES CATEGORIES
- Algorithms (22)
- All (399)
- Biography (1)
- Blog (44)
- Business Requirements (1)
- Commentary (1)
- Conversion (2)
- Customers (2)
- Data Models (1)
- Education (2)
- GeoRaptor (13)
- GPS (1)
- Image Processing (2)
- Import Export (8)
- Licensing (2)
- LiDAR (1)
- Linear Referencing (4)
- Manifold GIS (3)
- Mapping (1)
- MySQL Spatial (7)
- Networking and Routing (including Optimization) (5)
- Open Source (18)
- Oracle Spatial and Locator (194)
- Partitioning (1)
- PostGIS (36)
- Projections (1)
- Published Articles (1)
- qGIS (1)
- Recommendations (1)
- Services (1)
- Software Change Log (1)
- Source Code (37)
- Space Curves (9)
- Spatial Database Functions (109)
- Spatial DB comparison (1)
- Spatial XML Processing (11)
- SQL Server Spatial (92)
- Standards (3)
- Stored Procedure (17)
- Tessellation or Gridding (10)
- Tools (2)
- Topological Relationships (1)
- Training (2)
- Triangulation (2)
Oracle’s SQL/MM Compliant Types
Folks, there has been much made that Oracle Spatial is proprietary and that alternate implementations had to be done because the Sdo_Geometry implementation is not SQL/MM compliant.
What many do not know is that, since 10gR1, Oracle has implemented a wrapper set of objects over the top of their Sdo_Geometry implementation (limitations in Oracle objects made this more difficult in earlier versions).
To illustrate this I have constructed a very simple sql script which I now include in-line. If you cut it out you will discover that it works. However, you have to install my packages into a schema call CODESYS to make it work as I do use the QuadTree generation code in the TESSELATE package to generate the ST_Polygon data.
My tests all ran fine on XE and 10gR2.
In summary. If you want to use SQL/MM compliant types then you can. There are some idiosyncrasies (standards are notorious for the “wiggle-room” they provide implementors) and some limitations that can and will be fixed but, as someone once famous said: “it just works!” (Aside: Though Oracle could have saved themselves a lot of grief by naming Sdo_Geometry as ST_Geometry 10 years ago.)
set timing on set linesize 120 set pagesize 1000 drop table my_points; create table my_points ( point_id RAW(64) primary key , geometry mdsys.ST_Point ) PCTUSED 99; Declare Type row_t is table of my_points%ROWTYPE index by PLS_INTEGER; v_Rows row_t; v_Row my_points%ROWTYPE; v_pt MDSYS.SDO_Point_Type := MDSYS.SDO_Point_Type(NULL,NULL,NULL); v_lo MDSYS.SDO_Point_Type := MDSYS.SDO_POINT_TYPE(100000,5200000,NULL); v_hi MDSYS.SDO_Point_Type := MDSYS.SDO_POINT_TYPE(300000,5300000,NULL); v_pk RAW(64); v_RowCount PLS_INTEGER := 1; v_Commit PLS_INTEGER := 2000; v_MaxPts PLS_INTEGER := 200000; bulk_errors EXCEPTION; PRAGMA EXCEPTION_INIT (bulk_errors, -24381); Begin << point_generation_loop &gt;&gt; For i In 1..v_MaxPts Loop v_pt.x := dbms_random.value(v_lo.x,v_hi.x); v_pt.y := dbms_random.value(v_lo.y,v_hi.y); v_Row.geometry := MDSYS.ST_Point(v_pt.x,v_pt.y); v_Row.point_id := codesys.tesselate.Space_Key(v_pt,v_lo,v_hi); v_Rows(v_RowCount) := v_Row; If ( Mod(v_RowCount,v_Commit) = 0 ) Then ForAll i In 1..v_RowCount Save Exceptions Insert Into my_points Values v_Rows(i); Commit; v_rowCount := 0; End If; v_rowCount := v_rowCount + 1; End Loop point_generation_loop; Exception When BULK_ERRORS Then << bulk_errors_loop &gt;&gt; For j In 1 .. SQL%BULK_EXCEPTIONS.COUNT Loop DBMS_OUTPUT.PUT_LINE ( 'Error from element #' || TO_CHAR(SQL%BULK_EXCEPTIONS(j).error_index) || ': ' || SQLERRM(SQL%BULK_EXCEPTIONS(j).error_code)); End Loop bulk_errors_loop; End; / Prompt Get Extent of data to test the insert ... SELECT min( a.geometry.st_x() ) as minx, max( a.geometry.st_x() ) as maxx, min( a.geometry.st_y() ) as miny, max( a.geometry.st_y() ) as maxy, count(*) as NumRecs FROM my_points a; Prompt Create Oracle Metadata Entry... DELETE FROM user_sdo_geom_metadata WHERE table_name = 'MY_POINTS'; COMMIT; INSERT INTO user_sdo_geom_metadata ( table_name, column_name, diminfo, srid) SELECT 'MY_POINTS','GEOMETRY.GEOM', MDSYS.SDO_DIM_ARRAY( MDSYS.SDO_DIM_ELEMENT('X', minx, maxx, 0.5), MDSYS.SDO_DIM_ELEMENT('Y', miny, maxy, 0.5)), NULL FROM ( SELECT TRUNC( min( a.geometry.st_x() ) - 1,0) as minx, ROUND( max( a.geometry.st_x() ) + 1,0) as maxx, TRUNC( min( a.geometry.st_y() ) - 1,0) as miny, ROUND( max( a.geometry.st_y() ) + 1,0) as maxy FROM my_points a); Prompt Create RTree index on point data ... DROP INDEX my_points_geometry; CREATE INDEX my_points_geometry ON my_points(geometry.geom) INDEXTYPE IS MDSYS.SPATIAL_INDEX PARAMETERS('sdo_indx_dims=2, layer_gtype=point'); set serveroutput on size 100000 Prompt Now create some polygons by quadtree tesselation of the space my_points occupies DECLARE v_quadid INTEGER; v_diminfo MDSYS.SDO_DIM_ARRAY; BEGIN SELECT diminfo INTO v_diminfo FROM user_sdo_geom_metadata WHERE table_name = 'MY_POINTS'; codesys.Tesselate.SetGeom2SQLMM; codesys.Tesselate.Initialise(5000, 'MY_POINTS', 'GEOMETRY.GEOM', 20); v_QuadId := codesys.Tesselate.QuadTree( v_diminfo ); END; / Prompt Create Primary Key on Quad.Quad_Id data ... ALTER TABLE quad ADD CONSTRAINT quad_quad_id_pk PRIMARY KEY (quad_id); Prompt Create RTree index on st_polygon data ... DROP INDEX quad_geometry; CREATE INDEX quad_geometry ON quad(geometry.geom) INDEXTYPE IS MDSYS.SPATIAL_INDEX PARAMETERS('sdo_indx_dims=2, layer_gtype=polygon'); Prompt Some ST_Polygon inspectors... SELECT q.geometry.ST_CoordDim() FROM quad q WHERE rownum < 2; SELECT q.geometry.ST_Dimension() FROM quad q WHERE rownum < 2; SELECT distinct q.geometry.ST_Area() FROM quad q; SELECT q.geometry.ST_Envelope() FROM quad q WHERE rownum < 2; SELECT q.geometry.ST_IsSimple() FROM quad q WHERE rownum < 2; SELECT q.geometry.ST_ExteriorRing() FROM quad q WHERE rownum < 2; SELECT distinct q.geometry.ST_ExteriorRing().ST_Length() FROM quad q; SELECT q.geometry.ST_Buffer(10) FROM quad q WHERE rownum < 2; SELECT q.geometry.ST_NumInteriorRing() FROM quad q WHERE rownum < 2; SELECT q.geometry.ST_Centroid() FROM quad q WHERE rownum < 2; set serveroutput on size 100000 declare v_coord number; v_point mdsys.st_point; v_linestring mdsys.st_linestring; begin SELECT q.geometry.ST_ExteriorRing() INTO v_linestring FROM quad q WHERE rownum &lt; 2; For v_i in 1..v_linestring.ST_NumPoints() Loop v_point := v_linestring.st_PointN(v_i); dbms_output.put_line('x='||v_point.St_X()||' y='||v_point.st_y()); End Loop; end; / Prompt This is where the problem is... no public methods for executing spatial searches using ST_* methods... Prompt If I am wrong... email me and I will change this posting. explain plan set statement_id = 'SQL/MM QUERY' for SELECT count(*) FROM quad q, my_points p WHERE q.quad_id = 43 AND p.geometry.ST_Within(q.geometry) = 1; SELECT * FROM TABLE(dbms_xplan.display('PLAN_TABLE','SQL/MM QUERY','TYPICAL')); Prompt One can get around it mixing Sdo_Geometry searching and ST_* geometric methods ... set timing on SELECT count(*) FROM quad q, my_points p WHERE q.quad_id = 43 AND SDO_Filter(p.geometry.geom,q.geometry.geom) = 'TRUE' AND p.geometry.ST_Within(q.geometry) = 1; Prompt Perhaps in 11g? Prompt Until then, I am looking at building a custom domain index and methods that use it... perhaps I will get this done in the next 3 months.. I have made a start but...
Documentation
- MySQL Spatial General Functions
- Oracle LRS Objects
- Oracle Spatial Exporter (Java + pl/SQL)
- Oracle Spatial Object Functions
- Oracle Spatial Object Functions (Multi Page)
- PostGIS pl/pgSQL Functions
- SC4O Oracle Java Topology Suite (Java + pl/SQL)
- SQL Server Spatial General TSQL Functions
- SQL Server Spatial LRS TSQL Functions