diff options
-rw-r--r-- | mysql-test/r/gis.result | 68 | ||||
-rw-r--r-- | mysql-test/t/gis.test | 126 | ||||
-rw-r--r-- | sql/gcalc_slicescan.cc | 4 | ||||
-rw-r--r-- | sql/item_create.cc | 130 | ||||
-rw-r--r-- | sql/item_func.h | 2 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 651 | ||||
-rw-r--r-- | sql/item_geofunc.h | 95 | ||||
-rw-r--r-- | sql/spatial.cc | 17 | ||||
-rw-r--r-- | sql/spatial.h | 4 |
9 files changed, 996 insertions, 101 deletions
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 70e52154082..baedf17152c 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -1326,6 +1326,18 @@ WHERE name = 'Route 5' AND aliases = 'Main Street'; IsEmpty(centerline) 0 +# Conformance Item T12 +SELECT IsSimple(shore) +FROM lakes +WHERE name = 'Blue Lake'; +IsSimple(shore) +1 +# Conformance Item T13 +SELECT AsText(ST_Boundary(boundary)) +FROM named_places +WHERE name = 'Goose Island'; +AsText(ST_Boundary(boundary)) +LINESTRING(67 13,67 18,59 18,59 13,67 13) # Conformance Item T14 SELECT AsText(Envelope(boundary)) FROM named_places @@ -1356,6 +1368,17 @@ FROM road_segments WHERE fid = 102; AsText(EndPoint(centerline)) POINT(44 31) +SELECT IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +FROM named_places +WHERE name = 'Goose Island'; +IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +1 +# Conformance Item T20 +SELECT IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +FROM named_places +WHERE name = 'Goose Island'; +IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +0 # Conformance Item T21 SELECT GLength(centerline) FROM road_segments @@ -1380,6 +1403,11 @@ FROM named_places WHERE name = 'Goose Island'; AsText(Centroid(boundary)) POINT(63 15.5) +SELECT ST_Contains(boundary, PointOnSurface(boundary)) +FROM named_places +WHERE name = 'Goose Island'; +ST_Contains(boundary, PointOnSurface(boundary)) +1 # Conformance Item T26 SELECT Area(boundary) FROM named_places @@ -1434,6 +1462,12 @@ FROM ponds WHERE fid = 120; AsText(Centroid(shores)) POINT(25 42) +# Conformance Item T35 +SELECT Contains(shores, PointOnSurface(shores)) +FROM ponds +WHERE fid = 120; +Contains(shores, PointOnSurface(shores)) +1 # Conformance Item T36 SELECT Area(shores) FROM ponds @@ -1462,6 +1496,20 @@ WHERE streams.name = 'Cam Stream' AND lakes.name = 'Blue Lake'; ST_Touches(centerline, shore) 1 +# Conformance Item T40 +SELECT ST_Within(footprint, boundary) +FROM named_places, buildings +WHERE named_places.name = 'Ashton' +AND buildings.address = '215 Main Street'; +ST_Within(footprint, boundary) +1 +# Conformance Item T41 +SELECT ST_Overlaps(forests.boundary, named_places.boundary) +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; +ST_Overlaps(forests.boundary, named_places.boundary) +1 # Conformance Item T42 SELECT Crosses(road_segments.centerline, divided_routes.centerlines) FROM road_segments, divided_routes @@ -1483,6 +1531,13 @@ WHERE forests.name = 'Green Forest' AND named_places.name = 'Ashton'; ST_Contains(forests.boundary, named_places.boundary) 0 +# Conformance Item T45 +SELECT ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; +ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') +1 # Conformance Item T46 SELECT ST_Distance(position, boundary) FROM bridges, named_places @@ -1490,6 +1545,13 @@ WHERE bridges.name = 'Cam Bridge' AND named_places.name = 'Ashton'; ST_Distance(position, boundary) 12 +# Conformance Item T47 +SELECT AsText(ST_Intersection(centerline, shore)) +FROM streams, lakes +WHERE streams.name = 'Cam Stream' +AND lakes.name = 'Blue Lake'; +AsText(ST_Intersection(centerline, shore)) +POINT(52 18) # Conformance Item T48 SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) FROM named_places, forests @@ -1516,6 +1578,12 @@ FROM buildings, bridges WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; count(*) 1 +# Conformance Item T52 +SELECT AsText(ConvexHull(shore)) +FROM lakes +WHERE lakes.name = 'Blue Lake'; +AsText(ConvexHull(shore)) +POLYGON((48 6,52 18,66 23,73 9,48 6)) DROP DATABASE gis_ogs; USE test; # diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 5dc5b48f32c..60642e5741c 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -1119,33 +1119,27 @@ FROM named_places WHERE name = 'Goose Island'; --echo # Conformance Item T10 -# TODO: ST_SRID() alias SELECT SRID(boundary) FROM named_places WHERE name = 'Goose Island'; --echo # Conformance Item T11 -# TODO: ST_IsEmpty() alias SELECT IsEmpty(centerline) FROM road_segments WHERE name = 'Route 5' AND aliases = 'Main Street'; -# FIXME: get wrong result:0, expected 1. -#--echo # Conformance Item T12 -# TODO: ST_IsSimple() alias -#SELECT IsSimple(shore) -#FROM lakes -#WHERE name = 'Blue Lake'; +--echo # Conformance Item T12 +SELECT IsSimple(shore) +FROM lakes +WHERE name = 'Blue Lake'; -# TODO: WL#2377 -#--echo # Conformance Item T13 -#SELECT AsText(Boundary((boundary),101) -#FROM named_places -#WHERE name = 'Goose Island'; +--echo # Conformance Item T13 +SELECT AsText(ST_Boundary(boundary)) +FROM named_places +WHERE name = 'Goose Island'; --echo # Conformance Item T14 -# TODO: ST_Envelope( ) alias # FIXME: we get anticlockwise, GIS suggests clockwise SELECT AsText(Envelope(boundary)) FROM named_places @@ -1170,122 +1164,100 @@ FROM road_segments WHERE fid = 102; --echo # Conformance Item T18 -# TODO: ST_EndPoint SELECT AsText(EndPoint(centerline)) FROM road_segments WHERE fid = 102; -# TODO: WL#2377 -#--echo # Conformance Item T19 -# TODO: ST_LineFromWKB() alias -#SELECT IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) -#FROM named_places -#WHERE name = 'Goose Island'; +SELECT IsClosed(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +FROM named_places +WHERE name = 'Goose Island'; -# TODO: WL#2377 -#--echo # Conformance Item T20 -#SELECT IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) -#FROM named_places -#WHERE name = 'Goose Island'; +--echo # Conformance Item T20 +SELECT IsRing(LineFromWKB(AsBinary(Boundary(boundary)),SRID(boundary))) +FROM named_places +WHERE name = 'Goose Island'; --echo # Conformance Item T21 -# TODO: ST_Length() alias SELECT GLength(centerline) FROM road_segments WHERE fid = 106; --echo # Conformance Item T22 -# TODO: ST_NumPoints() alias SELECT NumPoints(centerline) FROM road_segments WHERE fid = 102; --echo # Conformance Item T23 -# TODO: ST_PointN() alias SELECT AsText(PointN(centerline, 1)) FROM road_segments WHERE fid = 102; --echo # Conformance Item T24 -# TODO: ST_Centroid() alias SELECT AsText(Centroid(boundary)) FROM named_places WHERE name = 'Goose Island'; -# TODO: WL#2377 -#--echo # Conformance Item T25 -#SELECT Contains(boundary, PointOnSurface(boundary)) -#FROM named_places -#WHERE name = 'Goose Island'; +SELECT ST_Contains(boundary, PointOnSurface(boundary)) +FROM named_places +WHERE name = 'Goose Island'; --echo # Conformance Item T26 -# TODO: ST_Area() alias SELECT Area(boundary) FROM named_places WHERE name = 'Goose Island'; --echo # Conformance Item T27 -# TODO: ST_ExteriorRing() alias SELECT AsText(ExteriorRing(shore)) FROM lakes WHERE name = 'Blue Lake'; --echo # Conformance Item T28 -# TODO: ST_NumInteriorRings() alias SELECT NumInteriorRings(shore) FROM lakes WHERE name = 'Blue Lake'; --echo # Conformance Item T29 -# TODO: ST_InteriorRingN() alias SELECT AsText(InteriorRingN(shore, 1)) FROM lakes WHERE name = 'Blue Lake'; --echo # Conformance Item T30 -# TODO: ST_NumGeometries() alias SELECT NumGeometries(centerlines) FROM divided_routes WHERE name = 'Route 75'; --echo # Conformance Item T31 -# TODO: ST_GeometryN() alias SELECT AsText(GeometryN(centerlines, 2)) FROM divided_routes WHERE name = 'Route 75'; --echo # Conformance Item T32 -# TODO: ST_IsClosed() alias SELECT IsClosed(centerlines) FROM divided_routes WHERE name = 'Route 75'; --echo # Conformance Item T33 -# TODO: ST_Length() alias SELECT GLength(centerlines) FROM divided_routes WHERE name = 'Route 75'; --echo # Conformance Item T34 -# TODO: ST_Centroid() alias SELECT AsText(Centroid(shores)) FROM ponds WHERE fid = 120; # TODO: WL#2377 -#--echo # Conformance Item T35 -#SELECT Contains(shores, PointOnSurface(shores)) -#FROM ponds -#WHERE fid = 120; +--echo # Conformance Item T35 +SELECT Contains(shores, PointOnSurface(shores)) +FROM ponds +WHERE fid = 120; --echo # Conformance Item T36 -# TODO: ST_Area() alias SELECT Area(shores) FROM ponds WHERE fid = 120; --echo # Conformance Item T37 -# TODO: ST_PolyFromText() alias SELECT ST_Equals(boundary, PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1)) FROM named_places @@ -1303,22 +1275,19 @@ FROM streams, lakes WHERE streams.name = 'Cam Stream' AND lakes.name = 'Blue Lake'; -# FIXME: wrong result: get 0, expected 1 -#--echo # Conformance Item T40 -#SELECT ST_Within(boundary, footprint) -#FROM named_places, buildings -#WHERE named_places.name = 'Ashton' -#AND buildings.address = '215 Main Street'; +--echo # Conformance Item T40 +SELECT ST_Within(footprint, boundary) +FROM named_places, buildings +WHERE named_places.name = 'Ashton' +AND buildings.address = '215 Main Street'; -# FIXME: wrong result: get 0, expected 1 -#--echo # Conformance Item T41 -#SELECT ST_Overlaps(forests.boundary, named_places.boundary) -#FROM forests, named_places -#WHERE forests.name = 'Green Forest' -#AND named_places.name = 'Ashton'; +--echo # Conformance Item T41 +SELECT ST_Overlaps(forests.boundary, named_places.boundary) +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; --echo # Conformance Item T42 -# FIXME: TODO: ST_Crosses() alias SELECT Crosses(road_segments.centerline, divided_routes.centerlines) FROM road_segments, divided_routes WHERE road_segments.fid = 102 @@ -1336,12 +1305,11 @@ FROM forests, named_places WHERE forests.name = 'Green Forest' AND named_places.name = 'Ashton'; -# TODO: WL#2377 -#--echo # Conformance Item T45 -#SELECT Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') -#FROM forests, named_places -#WHERE forests.name = 'Green Forest' -#AND named_places.name = 'Ashton'; +--echo # Conformance Item T45 +SELECT ST_Relate(forests.boundary, named_places.boundary, 'TTTTTTTTT') +FROM forests, named_places +WHERE forests.name = 'Green Forest' +AND named_places.name = 'Ashton'; --echo # Conformance Item T46 SELECT ST_Distance(position, boundary) @@ -1349,12 +1317,11 @@ FROM bridges, named_places WHERE bridges.name = 'Cam Bridge' AND named_places.name = 'Ashton'; -# FIXME: wrong result: NULL, expected 12 -#--echo # Conformance Item T47 -#SELECT AsText(ST_Intersection(centerline, shore)) -#FROM streams, lakes -#WHERE streams.name = 'Cam Stream' -#AND lakes.name = 'Blue Lake'; +--echo # Conformance Item T47 +SELECT AsText(ST_Intersection(centerline, shore)) +FROM streams, lakes +WHERE streams.name = 'Cam Stream' +AND lakes.name = 'Blue Lake'; --echo # Conformance Item T48 SELECT AsText(ST_Difference(named_places.boundary, forests.boundary)) @@ -1379,11 +1346,10 @@ SELECT count(*) FROM buildings, bridges WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1; -# TODO: WL#2377 -#--echo # Conformance Item T52 -#SELECT AsText(ConvexHull(shore)) -#FROM lakes -#WHERE lakes.name = 'Blue Lake'; +--echo # Conformance Item T52 +SELECT AsText(ConvexHull(shore)) +FROM lakes +WHERE lakes.name = 'Blue Lake'; DROP DATABASE gis_ogs; USE test; diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 251869cad03..ed533abdaf4 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -1961,7 +1961,7 @@ double Gcalc_scan_iterator::get_h() const state.pi->calc_xy(&x, &next_y); } else - next_y= state.pi->y; + next_y= state.pi->next ? state.pi->get_next()->y : 0.0; return next_y - cur_y; } @@ -1974,7 +1974,7 @@ double Gcalc_scan_iterator::get_sp_x(const point *sp) const dy= sp->next_pi->y - sp->pi->y; if (fabs(dy) < 1e-12) return sp->pi->x; - return (sp->next_pi->x - sp->pi->x) * dy; + return sp->pi->x + (sp->next_pi->x - sp->pi->x) * dy; } diff --git a/sql/item_create.cc b/sql/item_create.cc index fa8249c3321..efc1d9d3504 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -513,7 +513,35 @@ protected: Create_func_centroid() {} virtual ~Create_func_centroid() {} }; -#endif + + +class Create_func_convexhull : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_convexhull s_singleton; + +protected: + Create_func_convexhull() {} + virtual ~Create_func_convexhull() {} +}; + + +class Create_func_pointonsurface : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_pointonsurface s_singleton; + +protected: + Create_func_pointonsurface() {} + virtual ~Create_func_pointonsurface() {} +}; + + +#endif /*HAVE_SPATIAL*/ class Create_func_char_length : public Create_func_arg1 @@ -1015,7 +1043,19 @@ protected: Create_func_envelope() {} virtual ~Create_func_envelope() {} }; -#endif + +class Create_func_boundary : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_boundary s_singleton; + +protected: + Create_func_boundary() {} + virtual ~Create_func_boundary() {} +}; +#endif /*HAVE_SPATIAL*/ #ifdef HAVE_SPATIAL @@ -1466,6 +1506,19 @@ protected: #ifdef HAVE_SPATIAL +class Create_func_relate : public Create_func_arg3 +{ +public: + virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3); + + static Create_func_relate s_singleton; + +protected: + Create_func_relate() {} + virtual ~Create_func_relate() {} +}; + + class Create_func_mbr_intersects : public Create_func_arg2 { public: @@ -1596,6 +1649,19 @@ protected: Create_func_isclosed() {} virtual ~Create_func_isclosed() {} }; + + +class Create_func_isring : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_isring s_singleton; + +protected: + Create_func_isring() {} + virtual ~Create_func_isring() {} +}; #endif @@ -3338,7 +3404,25 @@ Create_func_centroid::create_1_arg(THD *thd, Item *arg1) { return new (thd->mem_root) Item_func_centroid(arg1); } -#endif + + +Create_func_convexhull Create_func_convexhull::s_singleton; + +Item* +Create_func_convexhull::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_convexhull(arg1); +} + + +Create_func_pointonsurface Create_func_pointonsurface::s_singleton; + +Item* +Create_func_pointonsurface::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_pointonsurface(arg1); +} +#endif /*HAVE_SPATIAL*/ Create_func_char_length Create_func_char_length::s_singleton; @@ -3819,6 +3903,15 @@ Create_func_envelope::create_1_arg(THD *thd, Item *arg1) { return new (thd->mem_root) Item_func_envelope(arg1); } + + +Create_func_boundary Create_func_boundary::s_singleton; + +Item* +Create_func_boundary::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_boundary(arg1); +} #endif @@ -4329,6 +4422,15 @@ Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2) #ifdef HAVE_SPATIAL +Create_func_relate Create_func_relate::s_singleton; + +Item* +Create_func_relate::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *matrix) +{ + return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2, matrix); +} + + Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton; Item* @@ -4429,10 +4531,17 @@ Create_func_isclosed::create_1_arg(THD *thd, Item *arg1) { return new (thd->mem_root) Item_func_isclosed(arg1); } -#endif -#ifdef HAVE_SPATIAL +Create_func_isring Create_func_isring::s_singleton; + +Item* +Create_func_isring::create_1_arg(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_isring(arg1); +} + + Create_func_isempty Create_func_isempty::s_singleton; Item* @@ -4440,7 +4549,7 @@ Create_func_isempty::create_1_arg(THD *thd, Item *arg1) { return new (thd->mem_root) Item_func_isempty(arg1); } -#endif +#endif /*HAVE_SPATIAL*/ Create_func_isnull Create_func_isnull::s_singleton; @@ -5656,6 +5765,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("BINLOG_GTID_POS") }, BUILDER(Create_func_binlog_gtid_pos)}, { { C_STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)}, { { C_STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)}, + { { C_STRING_WITH_LEN("BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)}, { { C_STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)}, { { C_STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)}, { { C_STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)}, @@ -5673,6 +5783,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)}, { { C_STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)}, { { C_STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)}, + { { C_STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)}, { { C_STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)}, { { C_STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)}, { { C_STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)}, @@ -5737,6 +5848,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, { { C_STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, { { C_STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)}, + { { C_STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)}, { { C_STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, { { C_STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)}, { { C_STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)}, @@ -5803,6 +5915,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { C_STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)}, + { { C_STRING_WITH_LEN("POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)}, { { C_STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { C_STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, @@ -5839,9 +5952,11 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)}, { { C_STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)}, { { C_STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)}, + { { C_STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)}, { { C_STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)}, { { C_STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)}, { { C_STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)}, + { { C_STRING_WITH_LEN("ST_CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)}, { { C_STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)}, { { C_STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)}, { { C_STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)}, @@ -5870,6 +5985,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)}, { { C_STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, { { C_STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, + { { C_STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)}, { { C_STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, { { C_STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)}, { { C_STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, @@ -5883,10 +5999,12 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { C_STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)}, + { { C_STRING_WITH_LEN("ST_POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)}, { { C_STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, { { C_STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { C_STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)}, + { { C_STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)}, { { C_STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)}, { { C_STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)}, { { C_STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)}, diff --git a/sql/item_func.h b/sql/item_func.h index 6c9d7e8af74..bc5f15ec16d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -61,7 +61,7 @@ public: SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC, SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC, SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING, - SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, + SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN, SP_RELATE_FUNC, NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index d9200b3e8d3..d38729771f8 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -218,6 +218,130 @@ String *Item_func_envelope::val_str(String *str) } +int Item_func_boundary::Transporter::single_point(double x, double y) +{ + return 0; +} + + +int Item_func_boundary::Transporter::start_line() +{ + n_points= 0; + current_type= Gcalc_function::shape_line; + return 0; +} + + +int Item_func_boundary::Transporter::complete_line() +{ + current_type= (Gcalc_function::shape_type) 0; + if (n_points > 1) + return m_receiver->single_point(last_x, last_y); + return 0; +} + + +int Item_func_boundary::Transporter::start_poly() +{ + current_type= Gcalc_function::shape_polygon; + return 0; +} + + +int Item_func_boundary::Transporter::complete_poly() +{ + current_type= (Gcalc_function::shape_type) 0; + return 0; +} + + +int Item_func_boundary::Transporter::start_ring() +{ + n_points= 0; + return m_receiver->start_shape(Gcalc_function::shape_line); +} + + +int Item_func_boundary::Transporter::complete_ring() +{ + if (n_points > 1) + { + m_receiver->add_point(last_x, last_y); + } + m_receiver->complete_shape(); + return 0; +} + + +int Item_func_boundary::Transporter::add_point(double x, double y) +{ + ++n_points; + if (current_type== Gcalc_function::shape_polygon) + { + /* Polygon's ring case */ + if (n_points == 1) + { + last_x= x; + last_y= y; + } + return m_receiver->add_point(x, y); + } + + if (current_type== Gcalc_function::shape_line) + { + /* Line's case */ + last_x= x; + last_y= y; + if (n_points == 1) + return m_receiver->single_point(x, y); + } + return 0; +} + + +int Item_func_boundary::Transporter::start_collection(int n_objects) +{ + return 0; +} + + +String *Item_func_boundary::val_str(String *str_value) +{ + DBUG_ENTER("Item_func_boundary::val_str"); + DBUG_ASSERT(fixed == 1); + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry_buffer buffer; + Geometry *g; + uint32 srid= 0; + Transporter trn(&res_receiver); + + if ((null_value= + args[0]->null_value || + !(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))) + DBUG_RETURN(0); + + if (g->store_shapes(&trn)) + goto mem_error; + + str_value->set_charset(&my_charset_bin); + if (str_value->reserve(SRID_SIZE, 512)) + goto mem_error; + str_value->length(0); + str_value->q_append(srid); + + if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver)) + goto mem_error; + + res_receiver.reset(); + DBUG_RETURN(str_value); + +mem_error: + null_value= 1; + DBUG_RETURN(0); +} + + Field::geometry_type Item_func_centroid::get_geometry_type() const { return Field::GEOM_POINT; @@ -248,6 +372,289 @@ String *Item_func_centroid::val_str(String *str) } +int Item_func_convexhull::add_node_to_line(ch_node **p_cur, int dir, + const Gcalc_heap::Info *pi) +{ + ch_node *new_node; + ch_node *cur= *p_cur; + + while (cur->prev) + { + int v_sign= Gcalc_scan_iterator::point::cmp_dx_dy( + cur->prev->pi, cur->pi, cur->pi, pi); + if (v_sign*dir <0) + break; + new_node= cur; + cur= cur->prev; + res_heap.free_item(new_node); + } + if (!(new_node= new_ch_node())) + return 1; + cur->next= new_node; + new_node->prev= cur; + new_node->pi= pi; + *p_cur= new_node; + return 0; +} + + +#ifndef HEAVY_CONVEX_HULL +String *Item_func_convexhull::val_str(String *str_value) +{ + Geometry_buffer buffer; + Geometry *geom= NULL; + MBR mbr; + const char *c_end; + Gcalc_operation_transporter trn(&func, &collector); + uint32 srid= 0; + ch_node *left_first, *left_cur, *right_first, *right_cur; + Gcalc_heap::Info *cur_pi; + + DBUG_ENTER("Item_func_convexhull::val_str"); + DBUG_ASSERT(fixed == 1); + String *swkb= args[0]->val_str(&tmp_value); + + if ((null_value= + args[0]->null_value || + !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))) + DBUG_RETURN(0); + + geom->get_mbr(&mbr, &c_end); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); + if ((null_value= geom->store_shapes(&trn))) + { + str_value= 0; + goto mem_error; + } + + collector.prepare_operation(); + if (!(cur_pi= collector.get_first())) + goto build_result; /* An EMPTY GEOMETRY */ + + if (!cur_pi->get_next()) + { + /* Single point. */ + if (res_receiver.single_point(cur_pi->x, cur_pi->y)) + goto mem_error; + goto build_result; + } + + left_cur= left_first= new_ch_node(); + right_cur= right_first= new_ch_node(); + right_first->prev= left_first->prev= 0; + right_first->pi= left_first->pi= cur_pi; + + while ((cur_pi= cur_pi->get_next())) + { + /* Handle left part of the hull, then the right part. */ + if (add_node_to_line(&left_cur, 1, cur_pi)) + goto mem_error; + if (add_node_to_line(&right_cur, -1, cur_pi)) + goto mem_error; + } + + left_cur->next= 0; + if (left_first->get_next()->get_next() == NULL && + right_cur->prev->prev == NULL) + { + /* We only have 2 nodes in the result, so we create a polyline. */ + if (res_receiver.start_shape(Gcalc_function::shape_line) || + res_receiver.add_point(left_first->pi->x, left_first->pi->y) || + res_receiver.add_point(left_cur->pi->x, left_cur->pi->y) || + res_receiver.complete_shape()) + + goto mem_error; + + goto build_result; + } + + if (res_receiver.start_shape(Gcalc_function::shape_polygon)) + goto mem_error; + + while (left_first) + { + if (res_receiver.add_point(left_first->pi->x, left_first->pi->y)) + goto mem_error; + left_first= left_first->get_next(); + } + + /* Skip last point in the right part as it coincides */ + /* with the last one in the left. */ + right_cur= right_cur->prev; + while (right_cur->prev) + { + if (res_receiver.add_point(right_cur->pi->x, right_cur->pi->y)) + goto mem_error; + right_cur= right_cur->prev; + } + res_receiver.complete_shape(); + +build_result: + str_value->set_charset(&my_charset_bin); + if (str_value->reserve(SRID_SIZE, 512)) + goto mem_error; + str_value->length(0); + str_value->q_append(srid); + + if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver)) + goto mem_error; + +mem_error: + collector.reset(); + func.reset(); + res_receiver.reset(); + res_heap.reset(); + DBUG_RETURN(str_value); +} + +#else /*HEAVY_CONVEX_HULL*/ +String *Item_func_convexhull::val_str(String *str_value) +{ + Geometry_buffer buffer; + Geometry *geom= NULL; + MBR mbr; + const char *c_end; + Gcalc_operation_transporter trn(&func, &collector); + const Gcalc_scan_iterator::event_point *ev; + uint32 srid= 0; + ch_node *left_first, *left_cur, *right_first, *right_cur; + + DBUG_ENTER("Item_func_convexhull::val_str"); + DBUG_ASSERT(fixed == 1); + String *swkb= args[0]->val_str(&tmp_value); + + if ((null_value= + args[0]->null_value || + !(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))) + DBUG_RETURN(0); + + geom->get_mbr(&mbr, &c_end); + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); + if ((null_value= geom->store_shapes(&trn))) + { + str_value= 0; + goto mem_error; + } + + collector.prepare_operation(); + scan_it.init(&collector); + scan_it.killed= (int *) &(current_thd->killed); + + if (!scan_it.more_points()) + goto build_result; /* An EMPTY GEOMETRY */ + + if (scan_it.step()) + goto mem_error; + + if (!scan_it.more_points()) + { + /* Single point. */ + if (res_receiver.single_point(scan_it.get_events()->pi->x, + scan_it.get_events()->pi->y)) + goto mem_error; + goto build_result; + } + + left_cur= left_first= new_ch_node(); + right_cur= right_first= new_ch_node(); + right_first->prev= left_first->prev= 0; + right_first->pi= left_first->pi= scan_it.get_events()->pi; + + while (scan_it.more_points()) + { + if (scan_it.step()) + goto mem_error; + ev= scan_it.get_events(); + + /* Skip the intersections-only events. */ + while (ev->event == scev_intersection) + { + ev= ev->get_next(); + if (!ev) + goto skip_point; + } + + { + Gcalc_point_iterator pit(&scan_it); + if (!pit.point() || scan_it.get_event_position() == pit.point()) + { + /* Handle left part of the hull. */ + if (add_node_to_line(&left_cur, 1, ev->pi)) + goto mem_error; + } + if (pit.point()) + { + /* Check the rightmost point */ + for(; pit.point()->c_get_next(); ++pit) + ; + } + if (!pit.point() || pit.point()->event || + scan_it.get_event_position() == pit.point()->c_get_next()) + { + /* Handle right part of the hull. */ + if (add_node_to_line(&right_cur, -1, ev->pi)) + goto mem_error; + } + } +skip_point:; + } + + left_cur->next= 0; + if (left_first->get_next()->get_next() == NULL && + right_cur->prev->prev == NULL) + { + /* We only have 2 nodes in the result, so we create a polyline. */ + if (res_receiver.start_shape(Gcalc_function::shape_line) || + res_receiver.add_point(left_first->pi->x, left_first->pi->y) || + res_receiver.add_point(left_cur->pi->x, left_cur->pi->y) || + res_receiver.complete_shape()) + + goto mem_error; + + goto build_result; + } + + if (res_receiver.start_shape(Gcalc_function::shape_polygon)) + goto mem_error; + + while (left_first) + { + if (res_receiver.add_point(left_first->pi->x, left_first->pi->y)) + goto mem_error; + left_first= left_first->get_next(); + } + + /* Skip last point in the right part as it coincides */ + /* with the last one in the left. */ + right_cur= right_cur->prev; + while (right_cur->prev) + { + if (res_receiver.add_point(right_cur->pi->x, right_cur->pi->y)) + goto mem_error; + right_cur= right_cur->prev; + } + res_receiver.complete_shape(); + +build_result: + str_value->set_charset(&my_charset_bin); + if (str_value->reserve(SRID_SIZE, 512)) + goto mem_error; + str_value->length(0); + str_value->q_append(srid); + + if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver)) + goto mem_error; + +mem_error: + collector.reset(); + func.reset(); + res_receiver.reset(); + res_heap.reset(); + DBUG_RETURN(str_value); +} +#endif /*HEAVY_CONVEX_HULL*/ + + /* Spatial decomposition functions */ @@ -593,12 +1000,17 @@ longlong Item_func_spatial_mbr_rel::val_int() Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) : - Item_bool_func2(a,b), collector() + Item_int_func(a,b), collector() { spatial_rel = sp_rel; } +Item_func_spatial_rel::Item_func_spatial_rel(Item *a,Item *b, Item *mask) : + Item_int_func(a,b,mask), spatial_rel(SP_RELATE_FUNC) +{} + + Item_func_spatial_rel::~Item_func_spatial_rel() { } @@ -623,6 +1035,8 @@ const char *Item_func_spatial_rel::func_name() const return "st_crosses"; case SP_OVERLAPS_FUNC: return "st_overlaps"; + case SP_RELATE_FUNC: + return "st_relate"; default: DBUG_ASSERT(0); // Should never happened return "sp_unknown"; @@ -661,6 +1075,84 @@ static double distance_points(const Gcalc_heap::Info *a, } +static Gcalc_function::op_type op_matrix(int n) +{ + switch (n) + { + case 0: + return Gcalc_function::op_border; + case 1: + return Gcalc_function::op_internals; + case 2: + return (Gcalc_function::op_type) + ((int) Gcalc_function::op_not | (int) Gcalc_function::op_union); + }; + GCALC_DBUG_ASSERT(FALSE); + return Gcalc_function::op_any; +} + + +static int setup_relate_func(Geometry *g1, Geometry *g2, + Gcalc_operation_transporter *trn, Gcalc_function *func, + const char *mask) +{ + int do_store_shapes=1; + uint shape_a, shape_b; + uint n_operands= 0; + int last_shape_pos; + + last_shape_pos= func->get_next_expression_pos(); + func->add_operation(Gcalc_function::op_intersection, 0); + for (int nc=0; nc<9; nc++) + { + uint cur_op; + + cur_op= Gcalc_function::op_intersection; + switch (mask[nc]) + { + case '*': + continue; + case 'T': + case '0': + case '1': + case '2': + cur_op|= Gcalc_function::v_find_t; + break; + case 'F': + cur_op|= Gcalc_function::v_find_f; + break; + }; + ++n_operands; + if (func->reserve_op_buffer(1)) + return 1; + func->add_operation(cur_op, 2); + + func->add_operation(op_matrix(nc/3), 1); + if (do_store_shapes) + { + shape_a= func->get_next_expression_pos(); + if (g1->store_shapes(trn)) + return 1; + } + else + func->repeat_expression(shape_a); + func->add_operation(op_matrix(nc%3), 1); + if (do_store_shapes) + { + shape_b= func->get_next_expression_pos(); + if (g2->store_shapes(trn)) + return 1; + do_store_shapes= 0; + } + else + func->repeat_expression(shape_b); + } + + func->add_operands_to_op(last_shape_pos, n_operands); + return 0; +} + + #define GIS_ZERO 0.00000000001 longlong Item_func_spatial_rel::val_int() @@ -669,6 +1161,7 @@ longlong Item_func_spatial_rel::val_int() DBUG_ASSERT(fixed == 1); String *res1; String *res2; + String *res3; Geometry_buffer buffer1, buffer2; Geometry *g1, *g2; int result= 0; @@ -736,6 +1229,8 @@ longlong Item_func_spatial_rel::val_int() case SP_OVERLAPS_FUNC: case SP_CROSSES_FUNC: func.add_operation(Gcalc_function::op_intersection, 2); + if (func.reserve_op_buffer(1)) + break; func.add_operation(Gcalc_function::v_find_t | Gcalc_function::op_intersection, 2); shape_a= func.get_next_expression_pos(); @@ -744,6 +1239,8 @@ longlong Item_func_spatial_rel::val_int() shape_b= func.get_next_expression_pos(); if ((null_value= g2->store_shapes(&trn))) break; + if (func.reserve_op_buffer(7)) + break; func.add_operation(Gcalc_function::v_find_t | Gcalc_function::op_intersection, 2); func.add_operation(Gcalc_function::v_find_t | @@ -756,6 +1253,8 @@ longlong Item_func_spatial_rel::val_int() func.repeat_expression(shape_a); break; case SP_TOUCHES_FUNC: + if (func.reserve_op_buffer(2)) + break; func.add_operation(Gcalc_function::op_intersection, 2); func.add_operation(Gcalc_function::v_find_f | Gcalc_function::op_not | @@ -775,6 +1274,13 @@ longlong Item_func_spatial_rel::val_int() func.add_operation(Gcalc_function::op_border, 1); func.repeat_expression(shape_b); break; + case SP_RELATE_FUNC: + res3= args[2]->val_str(&tmp_matrix); + if ((null_value= args[2]->null_value)) + break; + null_value= (res3->length() != 9) || + setup_relate_func(g1, g2, &trn, &func, res3->ptr()); + break; default: DBUG_ASSERT(FALSE); break; @@ -859,7 +1365,7 @@ String *Item_func_spatial_operation::val_str(String *str_value) str_value->length(0); str_value->q_append(srid); - if (Geometry::create_from_opresult(&buffer1, str_value, res_receiver)) + if (!Geometry::create_from_opresult(&buffer1, str_value, res_receiver)) goto exit; exit: @@ -1319,7 +1825,7 @@ String *Item_func_buffer::val_str(String *str_value) str_value->length(0); str_value->q_append(srid); - if (Geometry::create_from_opresult(&buffer, str_value, res_receiver)) + if (!Geometry::create_from_opresult(&buffer, str_value, res_receiver)) goto mem_error; null_value= 0; @@ -1423,6 +1929,30 @@ longlong Item_func_isclosed::val_int() return (longlong) isclosed; } + +longlong Item_func_isring::val_int() +{ + /* It's actually a combination of two functions - IsClosed and IsSimple */ + DBUG_ASSERT(fixed == 1); + String tmp; + String *swkb= args[0]->val_str(&tmp); + Geometry_buffer buffer; + Geometry *geom; + int isclosed= 0; // In case of error + + null_value= (!swkb || + args[0]->null_value || + !(geom= + Geometry::construct(&buffer, swkb->ptr(), swkb->length())) || + geom->is_closed(&isclosed)); + + if (!isclosed) + return 0; + + return Item_func_issimple::val_int(); +} + + /* Numerical functions */ @@ -1739,6 +2269,121 @@ mem_error: } +String *Item_func_pointonsurface::val_str(String *str) +{ + Gcalc_operation_transporter trn(&func, &collector); + + DBUG_ENTER("Item_func_pointonsurface::val_real"); + DBUG_ASSERT(fixed == 1); + String *res= args[0]->val_str(&tmp_value); + Geometry_buffer buffer; + Geometry *g; + MBR mbr; + const char *c_end; + double px, py, x0, y0; + String *result= 0; + const Gcalc_scan_iterator::point *pprev= NULL; + uint32 srid; + + + null_value= 1; + if ((args[0]->null_value || + !(g= Geometry::construct(&buffer, res->ptr(), res->length())) || + g->get_mbr(&mbr, &c_end))) + goto mem_error; + + collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); + + if (g->store_shapes(&trn)) + goto mem_error; + + collector.prepare_operation(); + scan_it.init(&collector); + + while (scan_it.more_points()) + { + if (scan_it.step()) + goto mem_error; + + if (scan_it.get_h() > GIS_ZERO) + { + y0= scan_it.get_y(); + break; + } + } + + if (!scan_it.more_points()) + { + goto exit; + } + + if (scan_it.step()) + goto mem_error; + + for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit) + { + if (pprev == NULL) + { + pprev= pit.point(); + continue; + } + x0= scan_it.get_sp_x(pprev); + px= scan_it.get_sp_x(pit.point()); + if (px - x0 > GIS_ZERO) + { + if (scan_it.get_h() > GIS_ZERO) + { + px= (px + x0) / 2.0; + py= scan_it.get_y(); + } + else + { + px= (px + x0) / 2.0; + py= (y0 + scan_it.get_y()) / 2.0; + } + null_value= 0; + break; + } + pprev= NULL; + } + + if (null_value) + goto exit; + + str->set_charset(&my_charset_bin); + if (str->reserve(SRID_SIZE, 512)) + goto mem_error; + + str->length(0); + srid= uint4korr(res->ptr()); + str->q_append(srid); + + if (Geometry::create_point(str, px, py)) + goto mem_error; + + result= str; + +exit: + collector.reset(); + func.reset(); + scan_it.reset(); + DBUG_RETURN(result); + +mem_error: + collector.reset(); + func.reset(); + scan_it.reset(); + null_value= 1; + DBUG_RETURN(0); +} + + +Field::geometry_type Item_func_pointonsurface::get_geometry_type() const +{ + return Field::GEOM_POINT; +} + + #ifndef DBUG_OFF longlong Item_func_gis_debug::val_int() { diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 6d52661e5c9..64863ed7d18 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -93,6 +93,39 @@ public: }; }; + +// #define HEAVY_CONVEX_HULL +class Item_func_convexhull: public Item_geometry_func +{ + class ch_node: public Gcalc_dyn_list::Item + { + public: + const Gcalc_heap::Info *pi; + ch_node *prev; + Gcalc_dyn_list::Item *next; + ch_node *get_next() { return (ch_node *) next; } + }; + + Gcalc_heap collector; + Gcalc_function func; + Gcalc_dyn_list res_heap; + + Gcalc_result_receiver res_receiver; + String tmp_value; +#ifdef HEAVY_CONVEX_HULL + Gcalc_scan_iterator scan_it; +#endif /*HEAVY_CONVEX_HULL*/ + ch_node *new_ch_node() { return (ch_node *) res_heap.new_item(); } + int add_node_to_line(ch_node **p_cur, int dir, const Gcalc_heap::Info *pi); +public: + Item_func_convexhull(Item *a): Item_geometry_func(a), + res_heap(8192, sizeof(ch_node)) + {} + const char *func_name() const { return "st_convexhull"; } + String *val_str(String *); +}; + + class Item_func_centroid: public Item_geometry_func { public: @@ -111,6 +144,38 @@ public: Field::geometry_type get_geometry_type() const; }; + +class Item_func_boundary: public Item_geometry_func +{ + class Transporter : public Gcalc_shape_transporter + { + Gcalc_result_receiver *m_receiver; + uint n_points; + Gcalc_function::shape_type current_type; + double last_x, last_y; + public: + Transporter(Gcalc_result_receiver *receiver) : + Gcalc_shape_transporter(NULL), m_receiver(receiver) + {} + int single_point(double x, double y); + int start_line(); + int complete_line(); + int start_poly(); + int complete_poly(); + int start_ring(); + int complete_ring(); + int add_point(double x, double y); + + int start_collection(int n_objects); + }; + Gcalc_result_receiver res_receiver; +public: + Item_func_boundary(Item *a): Item_geometry_func(a) {} + const char *func_name() const { return "st_boundary"; } + String *val_str(String *); +}; + + class Item_func_point: public Item_geometry_func { public: @@ -229,15 +294,16 @@ public: }; -class Item_func_spatial_rel: public Item_bool_func2 +class Item_func_spatial_rel: public Item_int_func { enum Functype spatial_rel; Gcalc_heap collector; Gcalc_scan_iterator scan_it; Gcalc_function func; - String tmp_value1,tmp_value2; + String tmp_value1,tmp_value2, tmp_matrix; public: Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel); + Item_func_spatial_rel(Item *a, Item *b, Item *matrix); virtual ~Item_func_spatial_rel(); longlong val_int(); enum Functype functype() const @@ -253,6 +319,9 @@ public: void fix_length_and_dec() { maybe_null= 1; } bool is_null() { (void) val_int(); return null_value; } + bool is_bool_func() { return 1; } + uint decimal_precision() const { return 1; } + optimize_type select_optimize() const { return OPTIMIZE_OP; } }; @@ -369,6 +438,14 @@ public: void fix_length_and_dec() { maybe_null= 1; } }; +class Item_func_isring: public Item_func_issimple +{ +public: + Item_func_isring(Item *a): Item_func_issimple(a) {} + longlong val_int(); + const char *func_name() const { return "st_isring"; } +}; + class Item_func_dimension: public Item_int_func { String value; @@ -497,6 +574,20 @@ public: }; +class Item_func_pointonsurface: public Item_geometry_func +{ + String tmp_value; + Gcalc_heap collector; + Gcalc_function func; + Gcalc_scan_iterator scan_it; +public: + Item_func_pointonsurface(Item *a): Item_geometry_func(a) {} + const char *func_name() const { return "st_pointonsurface"; } + String *val_str(String *); + Field::geometry_type get_geometry_type() const; +}; + + #ifndef DBUG_OFF class Item_func_gis_debug: public Item_int_func { diff --git a/sql/spatial.cc b/sql/spatial.cc index 34d2417f632..9f672801c9f 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -291,19 +291,18 @@ Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer, } -int Geometry::create_from_opresult(Geometry_buffer *g_buf, +Geometry *Geometry::create_from_opresult(Geometry_buffer *g_buf, String *res, Gcalc_result_receiver &rr) { uint32 geom_type= rr.get_result_typeid(); Geometry *obj= create_by_typeid(g_buf, geom_type); if (!obj || res->reserve(WKB_HEADER_SIZE, 512)) - return 1; + return NULL; res->q_append((char) wkb_ndr); res->q_append(geom_type); - return obj->init_from_opresult(res, rr.result(), rr.length()) == 0 && - rr.length(); + return obj->init_from_opresult(res, rr.result(), rr.length()) ? obj : NULL; } @@ -386,7 +385,7 @@ bool Geometry::create_point(String *result, const char *data) const 1 Can't reallocate 'result' */ -bool Geometry::create_point(String *result, double x, double y) const +bool Geometry::create_point(String *result, double x, double y) { if (result->reserve(1 + 4 + POINT_DATA_SIZE)) return 1; @@ -2221,6 +2220,13 @@ uint Gis_geometry_collection::init_from_opresult(String *bin, return 0; bin->q_append(n_objects); + if (res_len == 0) + { + /* Special case of GEOMETRYCOLLECTION EMPTY. */ + opres+= 1; + goto empty_geom; + } + while (res_len) { switch ((Gcalc_function::shape_type) uint4korr(opres)) @@ -2244,6 +2250,7 @@ uint Gis_geometry_collection::init_from_opresult(String *bin, res_len-= g_len; n_objects++; } +empty_geom: bin->write_at_position(no_pos, n_objects); return (uint) (opres - opres_orig); } diff --git a/sql/spatial.h b/sql/spatial.h index 3a6055add06..b850d405228 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -298,7 +298,7 @@ public: bool init_stream=1); static Geometry *create_from_wkb(Geometry_buffer *buffer, const char *wkb, uint32 len, String *res); - static int create_from_opresult(Geometry_buffer *g_buf, + static Geometry *create_from_opresult(Geometry_buffer *g_buf, String *res, Gcalc_result_receiver &rr); int as_wkt(String *wkt, const char **end); @@ -316,6 +316,7 @@ public: bool envelope(String *result) const; static Class_info *ci_collection[wkb_last+1]; + static bool create_point(String *result, double x, double y); protected: static Class_info *find_class(int type_id) { @@ -326,7 +327,6 @@ protected: const char *append_points(String *txt, uint32 n_points, const char *data, uint32 offset) const; bool create_point(String *result, const char *data) const; - bool create_point(String *result, double x, double y) const; const char *get_mbr_for_points(MBR *mbr, const char *data, uint offset) const; |