Commit 97327557 authored by StefanoPetrilli's avatar StefanoPetrilli Committed by Sergei Golubchik

MDEV-34276: Implements the function ST_IsValid

The GIS function ST_IsValid takes ad input a geometry and returns 1
if the argument is geometrically valid, 0 if the argument is not
geometrically valid.

Author: StefanoPetrilli <stefanop_1999@hotmail.it>
Co-authored-by: default avatarAhmed Ibrahim <ahmed.ibr.hashim@gmail.com>
Co-authored-by: default avatarJon Olav Hauglid <jon.hauglid@oracle.com>
Co-authored-by: default avatarErlend Dahl <erlend.dahl@oracle.com>
Co-authored-by: default avatarNorvald H. Ryeng <norvald.ryeng@oracle.com>
Co-authored-by: default avatarMenelaos Karavelas <menelaos.karavelas@oracle.com>
Co-authored-by: default avatarDavid.Zhao <david.zhao@oracle.com>
Co-authored-by: default avatarPavan <pavan.naik@oracle.com>
parent 70e646bd
...@@ -4582,6 +4582,12 @@ SELECT ST_ISSIMPLE(1); ...@@ -4582,6 +4582,12 @@ SELECT ST_ISSIMPLE(1);
ERROR HY000: Illegal parameter data type int for operation 'st_issimple' ERROR HY000: Illegal parameter data type int for operation 'st_issimple'
SELECT ST_ISSIMPLE('test'); SELECT ST_ISSIMPLE('test');
ERROR HY000: Illegal parameter data type varchar for operation 'st_issimple' ERROR HY000: Illegal parameter data type varchar for operation 'st_issimple'
SELECT ST_ISVALID(ROW(1,1));
ERROR HY000: Illegal parameter data type row for operation 'st_isvalid'
SELECT ST_ISVALID(1);
ERROR HY000: Illegal parameter data type int for operation 'st_isvalid'
SELECT ST_ISVALID('test');
ERROR HY000: Illegal parameter data type varchar for operation 'st_isvalid'
SELECT ST_ISRING(ROW(1,1)); SELECT ST_ISRING(ROW(1,1));
ERROR HY000: Illegal parameter data type row for operation 'st_isring' ERROR HY000: Illegal parameter data type row for operation 'st_isring'
SELECT ST_ISRING(1); SELECT ST_ISRING(1);
...@@ -5501,3 +5507,48 @@ ERROR HY000: Cannot cast 'point' as 'int' in assignment of `test`.`t1`.`b` ...@@ -5501,3 +5507,48 @@ ERROR HY000: Cannot cast 'point' as 'int' in assignment of `test`.`t1`.`b`
# #
# End of 11.5 tests # End of 11.5 tests
# #
#
# Start of 11.6 tests
#
#
# MDEV-34276 Tests for ST_isValid
#
# Some tests for Point, multipoint, linestring
SET @g = ST_GEOMFROMTEXT('POINT(0 0)');
SELECT ST_ISVALID(@g);
ST_ISVALID(@g)
1
SELECT ISVALID(@g);
ISVALID(@g)
1
SET @g = ST_GEOMFROMTEXT('POINT(15 0)');
SELECT ST_ISVALID(@g);
ST_ISVALID(@g)
1
SET @g = ST_GEOMFROMTEXT('MULTIPOINT(15 0, 10 0, 0 0, 11 11)');
SELECT ST_ISVALID(@g);
ST_ISVALID(@g)
1
SET @g = ST_GEOMFROMTEXT('LINESTRING(0 0, 1 1, 2 2, 2 3)');
SELECT ST_ISVALID(@g);
ST_ISVALID(@g)
1
# Some tests for Polygons
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))'));
ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))'))
1
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))'));
ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))'))
1
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((0 0, 0 2, 2 2, 1 1, 2 0, 0 0))'));
ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((0 0, 0 2, 2 2, 1 1, 2 0, 0 0))'))
1
SELECT ST_ISVALID(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 0, 0 2, 2 2, 2 0, 0 0)),((4 4, 4 5, 5 5, 5 4, 4 4)))')) AS a;
a
1
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (15 15, 15 20, 20 20, 20 15, 15 15))')) as t;
t
0
#
# End of 11.6 tests
#
...@@ -2625,6 +2625,13 @@ SELECT ST_ISSIMPLE(1); ...@@ -2625,6 +2625,13 @@ SELECT ST_ISSIMPLE(1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
SELECT ST_ISSIMPLE('test'); SELECT ST_ISSIMPLE('test');
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
SELECT ST_ISVALID(ROW(1,1));
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
SELECT ST_ISVALID(1);
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
SELECT ST_ISVALID('test');
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
SELECT ST_ISRING(ROW(1,1)); SELECT ST_ISRING(ROW(1,1));
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION --error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
...@@ -3503,3 +3510,42 @@ CREATE TABLE t1 (a POINT, b INT GENERATED ALWAYS AS (a)); ...@@ -3503,3 +3510,42 @@ CREATE TABLE t1 (a POINT, b INT GENERATED ALWAYS AS (a));
--echo # --echo #
--echo # End of 11.5 tests --echo # End of 11.5 tests
--echo # --echo #
--echo #
--echo # Start of 11.6 tests
--echo #
--echo #
--echo # MDEV-34276 Tests for ST_isValid
--echo #
--echo # Some tests for Point, multipoint, linestring
SET @g = ST_GEOMFROMTEXT('POINT(0 0)');
SELECT ST_ISVALID(@g);
SELECT ISVALID(@g);
SET @g = ST_GEOMFROMTEXT('POINT(15 0)');
SELECT ST_ISVALID(@g);
SET @g = ST_GEOMFROMTEXT('MULTIPOINT(15 0, 10 0, 0 0, 11 11)');
SELECT ST_ISVALID(@g);
SET @g = ST_GEOMFROMTEXT('LINESTRING(0 0, 1 1, 2 2, 2 3)');
SELECT ST_ISVALID(@g);
--echo # Some tests for Polygons
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))'));
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))'));
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((0 0, 0 2, 2 2, 1 1, 2 0, 0 0))'));
SELECT ST_ISVALID(ST_GEOMFROMTEXT('MULTIPOLYGON(((0 0, 0 2, 2 2, 2 0, 0 0)),((4 4, 4 5, 5 5, 5 4, 4 4)))')) AS a;
SELECT ST_ISVALID(ST_GEOMFROMTEXT('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (15 15, 15 20, 20 20, 20 15, 15 15))')) as t;
--echo #
--echo # End of 11.6 tests
--echo #
This diff is collapsed.
This diff is collapsed.
...@@ -2073,6 +2073,29 @@ String *Item_func_buffer::val_str(String *str_value) ...@@ -2073,6 +2073,29 @@ String *Item_func_buffer::val_str(String *str_value)
DBUG_RETURN(str_result); DBUG_RETURN(str_result);
} }
longlong Item_func_isvalid::val_int()
{
String *wkb= args[0]->val_str(&tmp);
Geometry_buffer buffer;
Geometry *geometry;
int valid;
if ((args[0]->null_value ||
!(geometry= Geometry::construct(&buffer, wkb->ptr(), wkb->length()))))
{
my_error(ER_GIS_INVALID_DATA, MYF(0), func_name());
null_value= 1;
return 1;
}
if (geometry->is_valid(&valid))
{
null_value= 1;
return 1;
}
return (longlong) valid;
}
longlong Item_func_isempty::val_int() longlong Item_func_isempty::val_int()
{ {
...@@ -2091,71 +2114,29 @@ longlong Item_func_issimple::val_int() ...@@ -2091,71 +2114,29 @@ longlong Item_func_issimple::val_int()
{ {
String *swkb= args[0]->val_str(&tmp); String *swkb= args[0]->val_str(&tmp);
Geometry_buffer buffer; Geometry_buffer buffer;
Gcalc_operation_transporter trn(&func, &collector); Geometry *geometry;
Geometry *g;
int result= 1;
MBR mbr;
const char *c_end;
DBUG_ENTER("Item_func_issimple::val_int"); DBUG_ENTER("Item_func_issimple::val_int");
DBUG_ASSERT(fixed()); DBUG_ASSERT(fixed());
null_value= 0; null_value= 0;
if ((args[0]->null_value || if ((args[0]->null_value ||
!(g= Geometry::construct(&buffer, swkb->ptr(), swkb->length())) || !(geometry= Geometry::construct(&buffer, swkb->ptr(), swkb->length()))))
g->get_mbr(&mbr, &c_end)))
{ {
/* We got NULL as an argument. Have to return -1 */ /* We got NULL as an argument. Have to return -1 */
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax); if (geometry->get_class_info()->m_type_id == Geometry::wkb_point)
if (g->get_class_info()->m_type_id == Geometry::wkb_point)
DBUG_RETURN(1); DBUG_RETURN(1);
if (g->store_shapes(&trn)) int simple;
goto mem_error; if (geometry->is_simple(&simple)) {
collector.prepare_operation();
scan_it.init(&collector);
while (scan_it.more_points())
{
const Gcalc_scan_iterator::event_point *ev, *next_ev;
if (scan_it.step())
goto mem_error;
ev= scan_it.get_events();
if (ev->simple_event())
continue;
next_ev= ev->get_next();
if ((ev->event & (scev_thread | scev_single_point)) && !next_ev)
continue;
if ((ev->event == scev_two_threads) && !next_ev->get_next())
continue;
/* If the first and last points of a curve coincide - that is */
/* an exception to the rule and the line is considered as simple. */
if ((next_ev && !next_ev->get_next()) &&
(ev->event & (scev_thread | scev_end)) &&
(next_ev->event & (scev_thread | scev_end)))
continue;
result= 0;
break;
}
collector.reset();
func.reset();
scan_it.reset();
DBUG_RETURN(result);
mem_error:
null_value= 1; null_value= 1;
DBUG_RETURN(0); DBUG_RETURN(0);
}
DBUG_RETURN(simple);
} }
...@@ -4230,6 +4211,22 @@ class Create_func_isempty : public Create_func_arg1 ...@@ -4230,6 +4211,22 @@ class Create_func_isempty : public Create_func_arg1
}; };
class Create_func_isvalid : public Create_func_arg1
{
public:
Item *create_1_arg(THD *thd, Item *arg1) override
{
return new (thd->mem_root) Item_func_isvalid(thd, arg1);
}
static Create_func_isvalid s_singleton;
protected:
Create_func_isvalid() = default;
virtual ~Create_func_isvalid() = default;
};
class Create_func_issimple : public Create_func_arg1 class Create_func_issimple : public Create_func_arg1
{ {
public: public:
...@@ -4246,7 +4243,6 @@ class Create_func_issimple : public Create_func_arg1 ...@@ -4246,7 +4243,6 @@ class Create_func_issimple : public Create_func_arg1
}; };
class Create_func_numgeometries : public Create_func_arg1 class Create_func_numgeometries : public Create_func_arg1
{ {
public: public:
...@@ -4516,6 +4512,7 @@ Create_func_intersection Create_func_intersection::s_singleton; ...@@ -4516,6 +4512,7 @@ Create_func_intersection Create_func_intersection::s_singleton;
Create_func_intersects Create_func_intersects::s_singleton; Create_func_intersects Create_func_intersects::s_singleton;
Create_func_isclosed Create_func_isclosed::s_singleton; Create_func_isclosed Create_func_isclosed::s_singleton;
Create_func_isempty Create_func_isempty::s_singleton; Create_func_isempty Create_func_isempty::s_singleton;
Create_func_isvalid Create_func_isvalid::s_singleton;
Create_func_isring Create_func_isring::s_singleton; Create_func_isring Create_func_isring::s_singleton;
Create_func_issimple Create_func_issimple::s_singleton; Create_func_issimple Create_func_issimple::s_singleton;
Create_func_mbr_contains Create_func_mbr_contains::s_singleton; Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
...@@ -4585,6 +4582,7 @@ static Native_func_registry func_array_geom[] = ...@@ -4585,6 +4582,7 @@ static Native_func_registry func_array_geom[] =
{ { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)}, { { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
{ { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, { { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
{ { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, { { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ISVALID") }, GEOM_BUILDER(Create_func_isvalid)},
{ { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)}, { { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)},
{ { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)}, { { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
...@@ -4668,6 +4666,7 @@ static Native_func_registry func_array_geom[] = ...@@ -4668,6 +4666,7 @@ static Native_func_registry func_array_geom[] =
{ { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)}, { { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
{ { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)}, { { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
{ { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)}, { { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ST_ISVALID") }, GEOM_BUILDER(Create_func_isvalid)},
{ { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)}, { { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)},
{ { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)}, { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)}, { { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
......
...@@ -955,9 +955,6 @@ class Item_func_isempty: public Item_bool_func_args_geometry ...@@ -955,9 +955,6 @@ class Item_func_isempty: public Item_bool_func_args_geometry
class Item_func_issimple: public Item_long_func_args_geometry class Item_func_issimple: public Item_long_func_args_geometry
{ {
Gcalc_heap collector;
Gcalc_function func;
Gcalc_scan_iterator scan_it;
String tmp; String tmp;
public: public:
Item_func_issimple(THD *thd, Item *a) Item_func_issimple(THD *thd, Item *a)
...@@ -1005,6 +1002,21 @@ class Item_func_isring: public Item_func_issimple ...@@ -1005,6 +1002,21 @@ class Item_func_isring: public Item_func_issimple
{ return get_item_copy<Item_func_isring>(thd, this); } { return get_item_copy<Item_func_isring>(thd, this); }
}; };
class Item_func_isvalid: public Item_long_func_args_geometry
{
public:
String tmp;
Item_func_isvalid(THD *thd, Item *a): Item_long_func_args_geometry(thd, a) {}
longlong val_int() override;
LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name= {STRING_WITH_LEN("st_isvalid") };
return name;
}
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_isvalid>(thd, this); }
};
class Item_func_dimension: public Item_long_func_args_geometry class Item_func_dimension: public Item_long_func_args_geometry
{ {
public: public:
......
...@@ -750,6 +750,56 @@ bool Geometry::envelope(String *result) const ...@@ -750,6 +750,56 @@ bool Geometry::envelope(String *result) const
return 0; return 0;
} }
int Geometry::is_simple(int *simple) const {
Gcalc_scan_iterator scan_it;
Gcalc_heap collector;
Gcalc_function func;
Gcalc_operation_transporter trn(&func, &collector);
const char *c_end;
MBR mbr;
*simple= 0;
if(this->get_mbr(&mbr, &c_end))
return 1;
collector.set_extent(mbr.xmin, mbr.xmax, mbr.ymin, mbr.ymax);
if (this->store_shapes(&trn))
return 1;
collector.prepare_operation();
scan_it.init(&collector);
while (scan_it.more_points())
{
const Gcalc_scan_iterator::event_point *ev, *next_ev;
if (scan_it.step())
return 1;
ev= scan_it.get_events();
if (ev->simple_event())
continue;
next_ev= ev->get_next();
if ((ev->event & (scev_thread | scev_single_point)) && !next_ev)
continue;
if ((ev->event == scev_two_threads) && !next_ev->get_next())
continue;
/* If the first and last points of a curve coincide - that is */
/* an exception to the rule and the line is considered as simple. */
if ((next_ev && !next_ev->get_next()) &&
(ev->event & (scev_thread | scev_end)) &&
(next_ev->event & (scev_thread | scev_end)))
continue;
return 0;
}
*simple= 1;
return 0;
}
/* /*
Create a point from data. Create a point from data.
...@@ -763,7 +813,6 @@ bool Geometry::envelope(String *result) const ...@@ -763,7 +813,6 @@ bool Geometry::envelope(String *result) const
0 ok 0 ok
1 Can't reallocate 'result' 1 Can't reallocate 'result'
*/ */
bool Geometry::create_point(String *result, const char *data) const bool Geometry::create_point(String *result, const char *data) const
{ {
if (no_data(data, POINT_DATA_SIZE) || if (no_data(data, POINT_DATA_SIZE) ||
...@@ -1045,6 +1094,17 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const ...@@ -1045,6 +1094,17 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const
} }
int Gis_point::is_valid(int *valid) const
{
double x, y;
if (get_xy(&x, &y))
return 1;
*valid= 1;
return 0;
}
int Gis_point::area(double *ar, const char **end) const int Gis_point::area(double *ar, const char **end) const
{ {
*ar= 0; *ar= 0;
...@@ -1444,6 +1504,47 @@ int Gis_line_string::is_closed(int *closed) const ...@@ -1444,6 +1504,47 @@ int Gis_line_string::is_closed(int *closed) const
} }
int Gis_line_string::is_valid(int *valid) const
{
Geometry_buffer buffer;
Geometry *geometry;
uint32 num_points;
*valid= 0;
if (no_data(m_data, 4))
return 1;
num_points= uint4korr(m_data);
if (not_enough_points(m_data, num_points))
return 1;
double x, y, previous_x, previous_y;
for (uint32 i = 1; i <= num_points; i++)
{
String wkb= 0;
if (wkb.reserve(SRID_SIZE + BYTE_ORDER_SIZE + WKB_HEADER_SIZE))
return 1;
wkb.q_append(SRID_PLACEHOLDER);
this->point_n(i, &wkb);
if (!(geometry= Geometry::construct(&buffer, wkb.ptr(), wkb.length()))||
((Gis_point *) geometry)->get_xy(&x, &y))
return 1;
if ((i != 1) && (x != previous_x || y != previous_y))
{
*valid= 1;
return 0;
}
previous_x = x;
previous_y = y;
}
return 0;
}
int Gis_line_string::num_points(uint32 *n_points) const int Gis_line_string::num_points(uint32 *n_points) const
{ {
*n_points= uint4korr(m_data); *n_points= uint4korr(m_data);
...@@ -1801,6 +1902,75 @@ bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const ...@@ -1801,6 +1902,75 @@ bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
} }
int Gis_polygon::is_valid(int *valid) const
{
Geometry *exterior_ring, *interior_ring;
MBR exterior_mbr, interior_mbr;
uint32 num_interior_ring;
Geometry_buffer buffer;
const char *c_end;
String wkb= 0;
*valid= 0;
if (wkb.reserve(SRID_SIZE + BYTE_ORDER_SIZE + WKB_HEADER_SIZE))
return 1;
wkb.q_append(SRID_PLACEHOLDER);
if (this->exterior_ring(&wkb) ||
!(exterior_ring= Geometry::construct(&buffer, wkb.ptr(), wkb.length())))
return 1;
int valid_ring, simple;
if (exterior_ring->is_valid(&valid_ring) ||
exterior_ring->is_simple(&simple))
return 1;
if (!valid_ring || !simple)
return 0;
if (exterior_ring->get_mbr(&exterior_mbr, &c_end) ||
this->num_interior_ring(&num_interior_ring))
return 1;
std::vector<MBR> interior_mbrs;
for(uint32 i= 1; i <= num_interior_ring; i++)
{
String interior_wkb= 0;
if (interior_wkb.reserve(SRID_SIZE + BYTE_ORDER_SIZE + WKB_HEADER_SIZE))
return 1;
interior_wkb.q_append(SRID_PLACEHOLDER);
if (this->interior_ring_n(i, &interior_wkb))
break;
if (!(interior_ring= Geometry::construct(&buffer, interior_wkb.ptr(),
interior_wkb.length())) ||
interior_ring->get_mbr(&interior_mbr, &c_end))
return 1;
if (!exterior_mbr.contains(&interior_mbr) ||
exterior_mbr.equals(&interior_mbr))
return 0;
if (interior_ring->is_simple(&simple))
return 1;
if (!simple)
return 0;
for (const auto &mbr : interior_mbrs)
{
if (interior_mbr.equals(&mbr) || interior_mbr.within(&mbr))
return 0;
}
interior_mbrs.push_back(interior_mbr);
}
*valid= 1;
return 0;
}
int Gis_polygon::area(double *ar, const char **end_of_data) const int Gis_polygon::area(double *ar, const char **end_of_data) const
{ {
uint32 n_linear_rings; uint32 n_linear_rings;
...@@ -2265,6 +2435,21 @@ bool Gis_multi_point::get_data_as_json(String *txt, uint max_dec_digits, ...@@ -2265,6 +2435,21 @@ bool Gis_multi_point::get_data_as_json(String *txt, uint max_dec_digits,
} }
int Gis_multi_point::is_valid(int *valid) const
{
uint32 num_points;
if (no_data(m_data, 4))
return 1;
num_points= uint4korr(m_data);
if (not_enough_points(m_data, num_points))
return 1;
*valid= 1;
return 0;
}
bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
{ {
return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0; return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
...@@ -2656,6 +2841,39 @@ bool Gis_multi_line_string::get_data_as_json(String *txt, uint max_dec_digits, ...@@ -2656,6 +2841,39 @@ bool Gis_multi_line_string::get_data_as_json(String *txt, uint max_dec_digits,
} }
int Gis_multi_line_string::is_valid(int *valid) const
{
uint32 num_linestring;
Geometry_buffer buffer;
Geometry *geometry= NULL;
*valid= 0;
if (no_data(m_data, 4))
return 1;
num_linestring= uint4korr(m_data);
for (uint32 i = 1; i <= num_linestring; i++)
{
String wkb = 0;
wkb.q_append(SRID_PLACEHOLDER);
if (this->geometry_n(i, &wkb) ||
!(geometry= Geometry::construct(&buffer, wkb.ptr(), wkb.length())))
return 1;
int line_valid;
if(geometry->is_valid(&line_valid))
return 1;
if (!line_valid)
return 0;
}
*valid= 1;
return 0;
}
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
{ {
uint32 n_line_strings; uint32 n_line_strings;
...@@ -3079,6 +3297,51 @@ bool Gis_multi_polygon::get_data_as_json(String *txt, uint max_dec_digits, ...@@ -3079,6 +3297,51 @@ bool Gis_multi_polygon::get_data_as_json(String *txt, uint max_dec_digits,
} }
int Gis_multi_polygon::is_valid(int *valid) const
{
Geometry_buffer buffer;
uint32 num_geometries;
std::vector<MBR> mbrs;
Geometry *geometry;
*valid= 0;
if (this->num_geometries(&num_geometries))
return 1;
for (uint32 i= 1; i <= num_geometries; i++)
{
String wkb= 0;
if (wkb.reserve(SRID_SIZE + BYTE_ORDER_SIZE + WKB_HEADER_SIZE))
return 0;
wkb.q_append(SRID_PLACEHOLDER);
if (this->geometry_n(i, &wkb) ||
!(geometry= Geometry::construct(&buffer, wkb.ptr(), wkb.length())))
return 1;
int internal_valid;
const char *c_end;
MBR interior_mbr;
if (geometry->is_valid(&internal_valid) ||
geometry->get_mbr(&interior_mbr, &c_end))
return 1;
if (!internal_valid)
return 0;
for (const auto &mbr : mbrs)
{
if (interior_mbr.intersects(&mbr) && !interior_mbr.touches(&mbr))
return 0;
}
mbrs.push_back(interior_mbr);
}
*valid= 1;
return 0;
}
bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
{ {
uint32 n_polygons; uint32 n_polygons;
...@@ -3551,6 +3814,41 @@ bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits, ...@@ -3551,6 +3814,41 @@ bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits,
} }
int Gis_geometry_collection::is_valid(int *valid) const
{
Geometry_buffer buffer;
uint32 num_geometries;
Geometry *geometry;
*valid= 0;
if (this->num_geometries(&num_geometries))
return 1;
for (uint32 i= 1; i <= num_geometries; i++)
{
String wkb= 0;
if (wkb.reserve(SRID_SIZE + BYTE_ORDER_SIZE + WKB_HEADER_SIZE))
return 1;
wkb.q_append(SRID_PLACEHOLDER);
if(this->geometry_n(i, &wkb) ||
!(geometry= Geometry::construct(&buffer, wkb.ptr(), wkb.length())))
return 1;
int internal_valid;
if (geometry->is_valid(&internal_valid))
return 1;
if (!internal_valid)
return 0;
}
*valid= 1;
return 0;
}
bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
{ {
uint32 n_objects; uint32 n_objects;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define SPATIAL_INCLUDED #define SPATIAL_INCLUDED
#include "sql_string.h" /* String, LEX_STRING */ #include "sql_string.h" /* String, LEX_STRING */
#include <vector>
#include <my_compiler.h> #include <my_compiler.h>
#include <json_lib.h> #include <json_lib.h>
...@@ -27,7 +28,9 @@ class Gis_read_stream; ...@@ -27,7 +28,9 @@ class Gis_read_stream;
#include "gcalc_tools.h" #include "gcalc_tools.h"
const uint SRID_SIZE= 4; const uint SRID_SIZE= 4;
const uint32 SRID_PLACEHOLDER= 0;
const uint SIZEOF_STORED_DOUBLE= 8; const uint SIZEOF_STORED_DOUBLE= 8;
const uint BYTE_ORDER_SIZE= 1;
const uint POINT_DATA_SIZE= (SIZEOF_STORED_DOUBLE * 2); const uint POINT_DATA_SIZE= (SIZEOF_STORED_DOUBLE * 2);
const uint WKB_HEADER_SIZE= 1+4; const uint WKB_HEADER_SIZE= 1+4;
const uint32 GET_SIZE_ERROR= ((uint32) -1); const uint32 GET_SIZE_ERROR= ((uint32) -1);
...@@ -289,6 +292,7 @@ class Geometry ...@@ -289,6 +292,7 @@ class Geometry
virtual int geom_length(double *len, const char **end) const { return -1; } virtual int geom_length(double *len, const char **end) const { return -1; }
virtual int area(double *ar, const char **end) const { return -1;} virtual int area(double *ar, const char **end) const { return -1;}
virtual int is_closed(int *closed) const { return -1; } virtual int is_closed(int *closed) const { return -1; }
virtual int is_valid(int *valid) const { return -1; }
virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; } virtual int num_interior_ring(uint32 *n_int_rings) const { return -1; }
virtual int num_points(uint32 *n_points) const { return -1; } virtual int num_points(uint32 *n_points) const { return -1; }
virtual int num_geometries(uint32 *num) const { return -1; } virtual int num_geometries(uint32 *num) const { return -1; }
...@@ -337,6 +341,7 @@ class Geometry ...@@ -337,6 +341,7 @@ class Geometry
} }
bool envelope(String *result) const; bool envelope(String *result) const;
int is_simple(int *simple) const;
static Class_info *ci_collection[wkb_last+1]; static Class_info *ci_collection[wkb_last+1];
static bool create_point(String *result, double x, double y); static bool create_point(String *result, double x, double y);
...@@ -405,7 +410,7 @@ class Gis_point: public Geometry ...@@ -405,7 +410,7 @@ class Gis_point: public Geometry
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int is_valid(int *valid) const override;
int get_xy(double *x, double *y) const int get_xy(double *x, double *y) const
{ {
const char *data= m_data; const char *data= m_data;
...@@ -479,6 +484,7 @@ class Gis_line_string: public Geometry ...@@ -479,6 +484,7 @@ class Gis_line_string: public Geometry
int area(double *ar, const char **end) const override; int area(double *ar, const char **end) const override;
int is_closed(int *closed) const override; int is_closed(int *closed) const override;
int num_points(uint32 *n_points) const override; int num_points(uint32 *n_points) const override;
int is_valid(int *valid) const override;
int start_point(String *point) const override; int start_point(String *point) const override;
int end_point(String *point) const override; int end_point(String *point) const override;
int point_n(uint32 n, String *result) const override; int point_n(uint32 n, String *result) const override;
...@@ -509,6 +515,7 @@ class Gis_polygon: public Geometry ...@@ -509,6 +515,7 @@ class Gis_polygon: public Geometry
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int is_valid(int *valid) const override;
int area(double *ar, const char **end) const override; int area(double *ar, const char **end) const override;
int exterior_ring(String *result) const override; int exterior_ring(String *result) const override;
int num_interior_ring(uint32 *n_int_rings) const override; int num_interior_ring(uint32 *n_int_rings) const override;
...@@ -545,6 +552,7 @@ class Gis_multi_point: public Geometry ...@@ -545,6 +552,7 @@ class Gis_multi_point: public Geometry
bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_wkt(String *txt, const char **end) const override;
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
int is_valid(int *valid) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int num_geometries(uint32 *num) const override; int num_geometries(uint32 *num) const override;
int geometry_n(uint32 num, String *result) const override; int geometry_n(uint32 num, String *result) const override;
...@@ -576,6 +584,7 @@ class Gis_multi_line_string: public Geometry ...@@ -576,6 +584,7 @@ class Gis_multi_line_string: public Geometry
bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_wkt(String *txt, const char **end) const override;
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
int is_valid(int *valid) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int num_geometries(uint32 *num) const override; int num_geometries(uint32 *num) const override;
int geometry_n(uint32 num, String *result) const override; int geometry_n(uint32 num, String *result) const override;
...@@ -606,6 +615,7 @@ class Gis_multi_polygon: public Geometry ...@@ -606,6 +615,7 @@ class Gis_multi_polygon: public Geometry
bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_wkt(String *txt, const char **end) const override;
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
int is_valid(int *valid) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int num_geometries(uint32 *num) const override; int num_geometries(uint32 *num) const override;
int geometry_n(uint32 num, String *result) const override; int geometry_n(uint32 num, String *result) const override;
...@@ -638,6 +648,7 @@ class Gis_geometry_collection: public Geometry ...@@ -638,6 +648,7 @@ class Gis_geometry_collection: public Geometry
bool get_data_as_wkt(String *txt, const char **end) const override; bool get_data_as_wkt(String *txt, const char **end) const override;
bool get_data_as_json(String *txt, uint max_dec_digits, bool get_data_as_json(String *txt, uint max_dec_digits,
const char **end) const override; const char **end) const override;
int is_valid(int *valid) const override;
bool get_mbr(MBR *mbr, const char **end) const override; bool get_mbr(MBR *mbr, const char **end) const override;
int area(double *ar, const char **end) const override; int area(double *ar, const char **end) const override;
int geom_length(double *len, const char **end) const override; int geom_length(double *len, const char **end) const override;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment