Skip to content

Commit 4b720b0

Browse files
Alexey BotchkovDaveGosselin-MariaDB
authored andcommitted
MDEV-35126 Wrong results from st_isvalid for multipolygon.
The Gis_polygon::is_valid() and the Gis_multi_polygon::is_valid() implemented with precise geometry engine.
1 parent 79a1fdd commit 4b720b0

File tree

8 files changed

+503
-87
lines changed

8 files changed

+503
-87
lines changed

mysql-test/main/spatial_utility_function_isvalid.result

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,42 @@ create or replace table tb1 as SELECT st_validate(POINTFROMTEXT(' POINT( 4 1 )
404404
create or replace table tb1 as SELECT st_validate(ST_GeomFromText (' linestring( 4 1,4 4 ) ')) a;
405405
create table tb2 as SELECT (st_validate (ST_collect(( POINTFROMTEXT(' POINT( 4 1 ) ') )) )) a;
406406
drop table tb1, tb2;
407+
########################################################################
408+
# MDEV-35126 Wrong results from st_isvalid or st_validate function, while using multipolygon.
409+
########################################################################
410+
select ST_isvalid(ST_GEOMFROMTEXT('multipolygon(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)), ((59 18,67 18,67 13,59 13,59 18)))'));
411+
ST_isvalid(ST_GEOMFROMTEXT('multipolygon(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)), ((59 18,67 18,67 13,59 13,59 18)))'))
412+
1
413+
select ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 6 0, 1 2, 0 0)), (( 7 7, 1 8, 7 0, 7 7 ))) '));
414+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 6 0, 1 2, 0 0)), (( 7 7, 1 8, 7 0, 7 7 ))) '))
415+
1
416+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((70 50, 80 50, 80 60, 70 60, 70 50)))'));
417+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((70 50, 80 50, 80 60, 70 60, 70 50)))'))
418+
0
419+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((90 50, 100 50, 100 60, 90 60, 90 50)))'));
420+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((90 50, 100 50, 100 60, 90 60, 90 50)))'))
421+
0
422+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((60 20, 70 20, 70 30, 60 30, 60 20)))'));
423+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((60 20, 70 20, 70 30, 60 30, 60 20)))'))
424+
1
425+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 120 210, 160 260, 140 260, 120 210)))'));
426+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 120 210, 160 260, 140 260, 120 210)))'))
427+
1
428+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 90 220, 110 240, 60 250, 90 220)))'));
429+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 90 220, 110 240, 60 250, 90 220)))'))
430+
0
431+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 5 5, 5 0, 0 5, 0 0)), (( 2 0, 3 0, 2 1, 2 0 ))) '));
432+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 5 5, 5 0, 0 5, 0 0)), (( 2 0, 3 0, 2 1, 2 0 ))) '))
433+
0
434+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 3 0, 0 3, 0 0)), (( 3 0, 3 3, 0 3, 3 0))) '));
435+
ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 3 0, 0 3, 0 0)), (( 3 0, 3 3, 0 3, 3 0))) '))
436+
0
437+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' POLYGON( ( 0 0, 0 0, 8 0, 0 0 ) ) '));
438+
ST_IsValid(ST_GEOMFROMTEXT(' POLYGON( ( 0 0, 0 0, 8 0, 0 0 ) ) '))
439+
0
440+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' MULTIPOLYGON( ( ( 2 2, 2 8, 8 8, 8 2, 2 2 ), ( 4 4, 4 6, 6 6, 6 4, 4 4 ) ), ( ( 2 2, 1 2, 0 5, 2 9, 2 2 ) ) ) ')) c;
441+
c
442+
0
443+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' MULTIPOLYGON( ( (2 2, 2 4, 4 4, 4 2, 2 2) ), ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) '));
444+
ST_IsValid(ST_GEOMFROMTEXT(' MULTIPOLYGON( ( (2 2, 2 4, 4 4, 4 2, 2 2) ), ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) '))
445+
0

mysql-test/main/spatial_utility_function_isvalid.test

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,31 @@ create or replace table tb1 as SELECT st_validate(POINTFROMTEXT(' POINT( 4 1 )
387387
create or replace table tb1 as SELECT st_validate(ST_GeomFromText (' linestring( 4 1,4 4 ) ')) a;
388388
create table tb2 as SELECT (st_validate (ST_collect(( POINTFROMTEXT(' POINT( 4 1 ) ') )) )) a;
389389
drop table tb1, tb2;
390+
391+
--echo ########################################################################
392+
--echo # MDEV-35126 Wrong results from st_isvalid or st_validate function, while using multipolygon.
393+
--echo ########################################################################
394+
select ST_isvalid(ST_GEOMFROMTEXT('multipolygon(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)), ((59 18,67 18,67 13,59 13,59 18)))'));
395+
396+
select ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 6 0, 1 2, 0 0)), (( 7 7, 1 8, 7 0, 7 7 ))) '));
397+
398+
# Concave shapes are not well-supported. This is correctly marked as invalid.
399+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((70 50, 80 50, 80 60, 70 60, 70 50)))'));
400+
401+
# Concave shapes are not well-supported. This is correctly marked as invalid.
402+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((90 50, 100 50, 100 60, 90 60, 90 50)))'));
403+
404+
# Concave shapes are not well-supported. This is incorrectly marked as invalid.
405+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 40 40, 80 40, 100 0, 120 40, 160 40, 130 70, 150 110, 100 90, 50 110, 70 70, 40 40)), ((60 20, 70 20, 70 30, 60 30, 60 20)))'));
406+
407+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 120 210, 160 260, 140 260, 120 210)))'));
408+
409+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 80 200, 110 210, 140 270, 70 280, 40 250, 60 220, 80 200)), (( 90 220, 110 240, 60 250, 90 220)))'));
410+
411+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 5 5, 5 0, 0 5, 0 0)), (( 2 0, 3 0, 2 1, 2 0 ))) '));
412+
SELECT ST_isvalid(ST_GEOMFROMTEXT(' MULTIPOLYGON((( 0 0, 3 0, 0 3, 0 0)), (( 3 0, 3 3, 0 3, 3 0))) '));
413+
414+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' POLYGON( ( 0 0, 0 0, 8 0, 0 0 ) ) '));
415+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' MULTIPOLYGON( ( ( 2 2, 2 8, 8 8, 8 2, 2 2 ), ( 4 4, 4 6, 6 6, 6 4, 4 4 ) ), ( ( 2 2, 1 2, 0 5, 2 9, 2 2 ) ) ) ')) c;
416+
SELECT ST_IsValid(ST_GEOMFROMTEXT(' MULTIPOLYGON( ( (2 2, 2 4, 4 4, 4 2, 2 2) ), ( (3 5, 2 5, 2 4, 3 4, 3 5) ) ) '));
417+

sql/gcalc_slicescan.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ class Gcalc_heap : public Gcalc_dyn_list
252252
#endif /*GCALC_CHECK_WITH_FLOAT*/
253253
double coord_extent;
254254
Gcalc_dyn_list::Item **get_cur_hook() { return m_hook; }
255+
int get_n_points() const { return m_n_points; }
255256

256257
private:
257258
Gcalc_dyn_list::Item *m_first;

sql/gcalc_tools.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
131131
uint n_ops= c_op & ~(op_any | op_not | v_mask);
132132
uint n_shape= c_op & ~(op_any | op_not | v_mask); /* same as n_ops */
133133
op_type v_state= (op_type) (c_op & v_mask);
134-
int result= 0;
134+
int result= 0, t_counter;
135135
const char *sav_cur_func= cur_func;
136136

137137
// GCALC_DBUG_ENTER("Gcalc_function::count_internal");
@@ -175,6 +175,11 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
175175
//GCALC_DBUG_RETURN(mask);
176176

177177
result= count_internal(cur_func, set_type, &cur_func);
178+
if (next_func == op_any_intersection)
179+
{
180+
t_counter= result == result_true;
181+
result= result_false;
182+
}
178183

179184
while (--n_ops)
180185
{
@@ -211,6 +216,10 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
211216
else
212217
result= result_true;
213218
break;
219+
case op_any_intersection:
220+
t_counter+= next_res == result_true;
221+
result= (t_counter > 1) ? result_true : result_false;
222+
break;
214223
default:
215224
GCALC_DBUG_ASSERT(FALSE);
216225
};

sql/gcalc_tools.h

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
op_intersection ( A && B && C ... )
3131
op_symdifference ( A+B+C+... == 1 )
3232
op_difference ( A && !(B||C||..))
33+
op_any_intersection ( A && B || A && C || ... || B && C ... )
3334
with the calls of the add_operation(operation, n_operands) method.
3435
The relation is calculated over a set of shapes, that in turn have
3536
to be added with the add_new_shape() method. All the 'shapes' can
@@ -55,23 +56,24 @@ class Gcalc_function
5556
enum op_type
5657
{
5758
v_empty= 0x00000000,
58-
v_find_t= 0x01000000,
59-
v_find_f= 0x02000000,
60-
v_t_found= 0x03000000,
61-
v_f_found= 0x04000000,
62-
v_mask= 0x07000000,
63-
64-
op_not= 0x80000000,
65-
op_shape= 0x00000000,
66-
op_union= 0x10000000,
67-
op_intersection= 0x20000000,
68-
op_symdifference= 0x30000000,
69-
op_difference= 0x40000000,
70-
op_repeat= 0x50000000,
71-
op_border= 0x60000000,
72-
op_internals= 0x70000000,
73-
op_false= 0x08000000,
74-
op_any= 0x78000000 /* The mask to get any of the operations */
59+
v_find_t= 0x00100000,
60+
v_find_f= 0x00200000,
61+
v_t_found= 0x00300000,
62+
v_f_found= 0x00400000,
63+
v_mask= 0x00700000,
64+
65+
op_not= 0x80000000,
66+
op_shape= 0x00000000,
67+
op_union= 0x10000000,
68+
op_intersection= 0x20000000,
69+
op_symdifference= 0x30000000,
70+
op_difference= 0x40000000,
71+
op_repeat= 0x50000000,
72+
op_border= 0x60000000,
73+
op_internals= 0x70000000,
74+
op_false= 0x08000000,
75+
op_any_intersection= 0x07000000,
76+
op_any= 0x7F000000 /* The mask to get any of the operations */
7577
};
7678
enum shape_type
7779
{
@@ -144,7 +146,7 @@ class Gcalc_operation_transporter : public Gcalc_shape_transporter
144146
gcalc_shape_info m_si;
145147
public:
146148
Gcalc_operation_transporter(Gcalc_function *fn, Gcalc_heap *heap) :
147-
Gcalc_shape_transporter(heap), m_fn(fn) {}
149+
Gcalc_shape_transporter(heap), m_fn(fn), m_si(0) {}
148150

149151
int single_point(double x, double y) override;
150152
int start_line() override;

sql/gstream.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,18 @@ class Gis_read_stream
3535
};
3636

3737
Gis_read_stream(CHARSET_INFO *charset, const char *buffer, int size)
38-
:m_cur(buffer), m_limit(buffer + size), m_err_msg(NULL), m_charset(charset)
38+
: m_wkt(buffer)
39+
, m_cur(buffer)
40+
, m_limit(buffer + size)
41+
, m_err_msg(NULL)
42+
, m_charset(charset)
3943
{}
40-
Gis_read_stream(): m_cur(NullS), m_limit(NullS), m_err_msg(NullS)
44+
45+
Gis_read_stream()
46+
: m_wkt(NullS)
47+
, m_cur(NullS)
48+
, m_limit(NullS)
49+
, m_err_msg(NullS)
4150
{}
4251
~Gis_read_stream()
4352
{
@@ -82,7 +91,13 @@ class Gis_read_stream
8291
return err_msg;
8392
}
8493

94+
const char *get_wkt() const
95+
{
96+
return m_wkt;
97+
}
98+
8599
protected:
100+
const char *const m_wkt;
86101
const char *m_cur;
87102
const char *m_limit;
88103
char *m_err_msg;

0 commit comments

Comments
 (0)