Commit fb3e3120 authored by Alexey Botchkov's avatar Alexey Botchkov

MDEV-7925 Inconsistent behavior of ST_Touches with a POINT as one of arguments.

        Some cases of the feature's borders were treated incorrectly.
parent 0357791e
......@@ -178,7 +178,7 @@ st_touches(geomfromtext('point(1 1)'), geomfromtext('point(1 1)'))
0
select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)'));
st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 1)'))
0
1
select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)'));
st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1 0)'))
0
......@@ -187,7 +187,7 @@ st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('point(1
0
select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))'));
st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1.2, 1 0, 2 0, 1 1.2))'))
1
0
select st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))'));
st_touches(geomfromtext('polygon((0 0, 2 2, 0 4, 0 0))'), geomfromtext('polygon((1 1, 1 0, 2 0, 1 1))'))
1
......@@ -437,7 +437,7 @@ ST_WITHIN( POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 2 0 , 1 0, 2 4 , 0 4, 0 5)
0
SELECT ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( ( (0 5, 3 5, 3 0, 0 0, 0 5), ( 1 1 , 2 1 , 2 4, 1 4, 1 1 ) ) ) '));
ST_WITHIN( POINTFROMTEXT(' POINT(1 2 ) ') , MULTIPOLYGONFROMTEXT(' MULTIPOLYGON( ( (0 5, 3 5, 3 0, 0 0, 0 5), ( 1 1 , 2 1 , 2 4, 1 4, 1 1 ) ) ) '))
0
1
select ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY')));
ST_ASTEXT(envelope(ST_GEOMCOLLFROMTEXT('GEOMETRYCOLLECTION EMPTY')))
GEOMETRYCOLLECTION EMPTY
......@@ -477,6 +477,15 @@ ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER( POLYGONFROMTEXT( 'POLYGON( ( 0.0 -3.0,
select astext(buffer(st_linestringfromwkb(linestring(point(-1,1), point(-1,-2))),-1));
astext(buffer(st_linestringfromwkb(linestring(point(-1,1), point(-1,-2))),-1))
GEOMETRYCOLLECTION EMPTY
select ST_Touches(ST_LineFromText('LINESTRING(0 0,5 5)'),ST_PointFromText('POINT(0 0)'));
ST_Touches(ST_LineFromText('LINESTRING(0 0,5 5)'),ST_PointFromText('POINT(0 0)'))
1
select ST_Touches(ST_PolygonFromText('POLYGON((0 0,0 5,5 5,5 0,0 0))'),ST_PointFromText('POINT(0 0)'));
ST_Touches(ST_PolygonFromText('POLYGON((0 0,0 5,5 5,5 0,0 0))'),ST_PointFromText('POINT(0 0)'))
1
select ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)'));
ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)'))
0
DROP TABLE IF EXISTS p1;
CREATE PROCEDURE p1(dist DOUBLE, geom TEXT)
BEGIN
......
......@@ -408,7 +408,7 @@ first second w c o e d t i r
120 122 NULL NULL NULL NULL NULL NULL NULL NULL
120 123 NULL NULL NULL NULL NULL NULL NULL NULL
121 120 0 0 1 0 0 0 1 0
121 121 1 1 0 1 0 1 1 0
121 121 1 1 0 1 0 0 1 0
121 122 NULL NULL NULL NULL NULL NULL NULL NULL
121 123 NULL NULL NULL NULL NULL NULL NULL NULL
122 120 NULL NULL NULL NULL NULL NULL NULL NULL
......@@ -877,7 +877,7 @@ mbroverlaps
down,left,right,up
SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrtouches FROM t1 a1 JOIN t1 a2 ON MBRTouches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name;
mbrtouches
big,center,down,down2,left,left2,right,right2,small,up,up2
down2,left2,right2,up2
SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS mbrwithin FROM t1 a1 JOIN t1 a2 ON MBRWithin( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name;
mbrwithin
big,center
......@@ -898,7 +898,7 @@ overlaps
down,left,right,up
SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS touches FROM t1 a1 JOIN t1 a2 ON Touches( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name;
touches
big,center,down,down2,left,left2,right,right2,small,up,up2
down2,left2,right2,up2
SELECT GROUP_CONCAT(a2.name ORDER BY a2.name) AS within FROM t1 a1 JOIN t1 a2 ON Within( a1.square, a2.square) WHERE a1.name = "center" GROUP BY a1.name;
within
big,center
......
......@@ -357,5 +357,10 @@ SELECT ST_NUMPOINTS(ST_EXTERIORRING(ST_BUFFER( POLYGONFROMTEXT( 'POLYGON( ( 0.0
# MDEV-5615 crash in Gcalc_function::add_operation
select astext(buffer(st_linestringfromwkb(linestring(point(-1,1), point(-1,-2))),-1));
# MDEV-7925 Inconsistent behavior of ST_Touches with a POINT as one of arguments
select ST_Touches(ST_LineFromText('LINESTRING(0 0,5 5)'),ST_PointFromText('POINT(0 0)'));
select ST_Touches(ST_PolygonFromText('POLYGON((0 0,0 5,5 5,5 0,0 0))'),ST_PointFromText('POINT(0 0)'));
select ST_Touches(ST_PointFromText('POINT(0 0)'),ST_PointFromText('POINT(0 0)'));
--source include/gis_debug.inc
......@@ -143,6 +143,9 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
{
if (set_type == 0)
result= i_states[n_shape] | b_states[n_shape];
/* the last call for the count_internal outside of all shapes. */
else if (set_type == 1)
result= 0;
else if (set_type == op_border)
result= b_states[n_shape];
else if (set_type == op_internals)
......@@ -158,7 +161,8 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
if (next_func == op_border || next_func == op_internals)
{
result= count_internal(cur_func, next_func, &cur_func);
result= count_internal(cur_func,
(set_type == 1) ? set_type : next_func, &cur_func);
goto exit;
}
......@@ -180,16 +184,34 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
switch (next_func)
{
case op_union:
result= result | next_res;
if (result == result_true || next_res == result_true)
result= result_true;
else if (result == result_unknown || next_res == result_unknown)
result= result_unknown;
else
result= result_false;
break;
case op_intersection:
result= result & next_res;
if (result == result_false || next_res == result_false)
result= result_false;
else if (result == result_unknown || next_res == result_unknown)
result= result_unknown;
else
result= result_true;
break;
case op_symdifference:
result= result ^ next_res;
if (result == result_unknown || next_res == result_unknown)
result= result_unknown;
else
result= result ^ next_res;
break;
case op_difference:
result= result & !next_res;
if (result == result_false || next_res == result_true)
result= result_false;
else if (result == result_unknown || next_res == result_unknown)
result= result_unknown;
else
result= result_true;
break;
default:
GCALC_DBUG_ASSERT(FALSE);
......@@ -197,24 +219,35 @@ int Gcalc_function::count_internal(const char *cur_func, uint set_type,
}
exit:
result^= mask;
if (result != result_unknown)
result^= mask;
if (v_state != v_empty)
{
switch (v_state)
{
case v_find_t:
if (result)
if (result == result_true)
{
c_op= (c_op & ~v_mask) | v_t_found;
int4store(sav_cur_func, c_op);
};
}
else
{
if (set_type != 1)
result= result_unknown;
}
break;
case v_find_f:
if (!result)
if (result == result_false)
{
c_op= (c_op & ~v_mask) | v_f_found;
int4store(sav_cur_func, c_op);
};
}
else
{
if (set_type != 1)
result= result_unknown;
}
break;
case v_t_found:
result= 1;
......@@ -264,6 +297,7 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
{
const Gcalc_scan_iterator::point *eq_start, *cur_eq;
const Gcalc_scan_iterator::event_point *events;
int result;
GCALC_DBUG_ENTER("Gcalc_function::check_function");
while (scan_it.more_points())
......@@ -288,8 +322,8 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
if (events->event == scev_end)
set_b_state(events->get_shape());
if (count())
GCALC_DBUG_RETURN(1);
if ((result= count()) != result_unknown)
GCALC_DBUG_RETURN(result);
clear_b_states();
continue;
}
......@@ -307,8 +341,8 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
set_i_state(si);
}
if (count())
GCALC_DBUG_RETURN(1);
if ((result= count()) != result_unknown)
GCALC_DBUG_RETURN(result);
/* Set back states changed in the loop above. */
for (events= scan_it.get_events(); events; events= events->get_next())
......@@ -316,10 +350,10 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
gcalc_shape_info si= events->get_shape();
if (events->event == scev_thread ||
events->event == scev_end ||
events->event == scev_single_point ||
(get_shape_kind(si) == Gcalc_function::shape_polygon))
get_shape_kind(si) == Gcalc_function::shape_polygon)
clear_b_state(si);
else if (get_shape_kind(si) == Gcalc_function::shape_line)
else if (events->event == scev_single_point ||
get_shape_kind(si) == Gcalc_function::shape_line)
clear_i_state(si);
}
......@@ -343,8 +377,8 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
else
invert_i_state(si);
}
if (count())
GCALC_DBUG_RETURN(1);
if ((result= count()) != result_unknown)
GCALC_DBUG_RETURN(result);
for (cur_eq= eq_start; cur_eq != pit.point(); cur_eq= cur_eq->get_next())
{
......@@ -357,12 +391,13 @@ int Gcalc_function::check_function(Gcalc_scan_iterator &scan_it)
else
invert_i_state(cur_eq->get_shape());
}
if (count())
GCALC_DBUG_RETURN(1);
if ((result= count()) != result_unknown)
GCALC_DBUG_RETURN(result);
eq_start= pit.point();
} while (pit.point() != scan_it.get_event_end());
}
GCALC_DBUG_RETURN(0);
GCALC_DBUG_RETURN(count_last());
}
......
......@@ -82,6 +82,12 @@ class Gcalc_function
shape_polygon= 2,
shape_hole= 3
};
enum count_result
{
result_false= 0,
result_true= 1,
result_unknown= 2
};
Gcalc_function() : n_shapes(0) {}
gcalc_shape_info add_new_shape(uint32 shape_id, shape_type shape_kind);
/*
......@@ -116,6 +122,8 @@ class Gcalc_function
int get_b_state(gcalc_shape_info shape) { return b_states[shape]; }
int count()
{ return count_internal(function_buffer.ptr(), 0, 0); }
int count_last()
{ return count_internal(function_buffer.ptr(), 1, 0); }
void clear_i_states();
void clear_b_states();
void reset();
......
......@@ -1104,8 +1104,10 @@ static int setup_relate_func(Geometry *g1, Geometry *g2,
cur_op|= Gcalc_function::v_find_t;
break;
case 'F':
cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_t);
cur_op|= (Gcalc_function::op_not | Gcalc_function::v_find_f);
break;
default:
return 1;
};
++n_operands;
if (func->reserve_op_buffer(3))
......@@ -1150,7 +1152,6 @@ longlong Item_func_spatial_precise_rel::val_int()
Geometry_buffer buffer1, buffer2;
Geometry *g1, *g2;
int result= 0;
int mask= 0;
uint shape_a, shape_b;
MBR umbr, mbr1, mbr2;
const char *c_end;
......@@ -1180,8 +1181,9 @@ longlong Item_func_spatial_precise_rel::val_int()
case SP_CONTAINS_FUNC:
if (!mbr1.contains(&mbr2))
goto exit;
mask= 1;
func.add_operation(Gcalc_function::op_difference, 2);
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_difference, 2);
/* Mind the g2 goes first. */
null_value= g2->store_shapes(&trn) || g1->store_shapes(&trn);
break;
......@@ -1189,32 +1191,36 @@ longlong Item_func_spatial_precise_rel::val_int()
mbr2.buffer(2e-5);
if (!mbr1.within(&mbr2))
goto exit;
mask= 1;
func.add_operation(Gcalc_function::op_difference, 2);
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_difference, 2);
null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_EQUALS_FUNC:
if (!mbr1.contains(&mbr2))
goto exit;
mask= 1;
func.add_operation(Gcalc_function::op_symdifference, 2);
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_symdifference, 2);
null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_DISJOINT_FUNC:
mask= 1;
func.add_operation(Gcalc_function::op_intersection, 2);
func.add_operation(Gcalc_function::v_find_f |
Gcalc_function::op_not |
Gcalc_function::op_intersection, 2);
null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_INTERSECTS_FUNC:
if (!mbr1.intersects(&mbr2))
goto exit;
func.add_operation(Gcalc_function::op_intersection, 2);
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2);
null_value= g1->store_shapes(&trn) || g2->store_shapes(&trn);
break;
case SP_OVERLAPS_FUNC:
case SP_CROSSES_FUNC:
func.add_operation(Gcalc_function::op_intersection, 2);
if (func.reserve_op_buffer(1))
if (func.reserve_op_buffer(3))
break;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2);
......@@ -1226,8 +1232,7 @@ longlong Item_func_spatial_precise_rel::val_int()
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::op_intersection, 2);
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_difference, 2);
func.repeat_expression(shape_a);
......@@ -1238,7 +1243,7 @@ longlong Item_func_spatial_precise_rel::val_int()
func.repeat_expression(shape_a);
break;
case SP_TOUCHES_FUNC:
if (func.reserve_op_buffer(2))
if (func.reserve_op_buffer(5))
break;
func.add_operation(Gcalc_function::op_intersection, 2);
func.add_operation(Gcalc_function::v_find_f |
......@@ -1254,9 +1259,7 @@ longlong Item_func_spatial_precise_rel::val_int()
break;
func.add_operation(Gcalc_function::v_find_t |
Gcalc_function::op_intersection, 2);
func.add_operation(Gcalc_function::op_border, 1);
func.repeat_expression(shape_a);
func.add_operation(Gcalc_function::op_border, 1);
func.repeat_expression(shape_b);
break;
case SP_RELATE_FUNC:
......@@ -1281,7 +1284,7 @@ longlong Item_func_spatial_precise_rel::val_int()
if (func.alloc_states())
goto exit;
result= func.check_function(scan_it) ^ mask;
result= func.check_function(scan_it);
exit:
collector.reset();
......
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