Skip to content

Commit 69f374e

Browse files
MDEV-35739 ST_INTERSECTION precise self-intersection
ST_INTERSECTION(geom_1, geom_1) returns geom_1 exactly. Replaces 'goto exit;' in Item_func_spatial_operation::val_str with SCOPE_EXIT. This was done to leverage existing geometry construction calls without incurring compiler errors caused by skipping initialization on goto.
1 parent 629b8d7 commit 69f374e

File tree

5 files changed

+91
-10
lines changed

5 files changed

+91
-10
lines changed

mysql-test/main/gis.result

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5507,3 +5507,24 @@ ST_SRID(g1) ST_SRID(ST_GeomFromWKB(g1, 4326)) ST_SRID(ST_GeomFromWKB(g1)) ST_AsT
55075507
SELECT ST_DISTANCE_SPHERE(st_geomfromtext('linestring( 2 2, 2 8) '), ST_GeomFromText('POINT(18.413076 43.856258)')) ;
55085508
ERROR HY000: Calling geometry function st_distance_sphere with unsupported types of arguments.
55095509
# End of 10.5 tests
5510+
#
5511+
# Start of 10.11 tests
5512+
#
5513+
#
5514+
# MDEV-35739 Linestring self-intersection equality
5515+
#
5516+
CREATE TABLE t1(geom geometry NOT NULL);
5517+
INSERT INTO t1 (geom) VALUES(ST_GeomFromText('LINESTRING(2 2,4 4,6 2,3 2,2 4)'));
5518+
SELECT ST_ASTEXT(geom) FROM t1;
5519+
ST_ASTEXT(geom)
5520+
LINESTRING(2 2,4 4,6 2,3 2,2 4)
5521+
SELECT ST_EQUALS(geom, ST_INTERSECTION(geom, geom)) AS isequal, ST_ASTEXT(ST_INTERSECTION(geom, geom)) AS intersection FROM t1;
5522+
isequal intersection
5523+
1 LINESTRING(2 2,4 4,6 2,3 2,2 4)
5524+
SELECT ST_AsText(ST_SYMDIFFERENCE(geom, ST_Intersection(geom, geom))) FROM t1;
5525+
ST_AsText(ST_SYMDIFFERENCE(geom, ST_Intersection(geom, geom)))
5526+
GEOMETRYCOLLECTION EMPTY
5527+
DROP TABLE t1;
5528+
#
5529+
# End of 10.11 tests
5530+
#

mysql-test/main/gis.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,3 +3515,21 @@ FROM (
35153515
SELECT ST_DISTANCE_SPHERE(st_geomfromtext('linestring( 2 2, 2 8) '), ST_GeomFromText('POINT(18.413076 43.856258)')) ;
35163516

35173517
--echo # End of 10.5 tests
3518+
3519+
--echo #
3520+
--echo # Start of 10.11 tests
3521+
--echo #
3522+
3523+
--echo #
3524+
--echo # MDEV-35739 Linestring self-intersection equality
3525+
--echo #
3526+
CREATE TABLE t1(geom geometry NOT NULL);
3527+
INSERT INTO t1 (geom) VALUES(ST_GeomFromText('LINESTRING(2 2,4 4,6 2,3 2,2 4)'));
3528+
SELECT ST_ASTEXT(geom) FROM t1;
3529+
SELECT ST_EQUALS(geom, ST_INTERSECTION(geom, geom)) AS isequal, ST_ASTEXT(ST_INTERSECTION(geom, geom)) AS intersection FROM t1;
3530+
SELECT ST_AsText(ST_SYMDIFFERENCE(geom, ST_Intersection(geom, geom))) FROM t1;
3531+
DROP TABLE t1;
3532+
3533+
--echo #
3534+
--echo # End of 10.11 tests
3535+
--echo #

sql/item_geofunc.cc

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,12 @@ String *Item_func_spatial_operation::val_str(String *str_value)
15471547
{
15481548
DBUG_ENTER("Item_func_spatial_operation::val_str");
15491549
DBUG_ASSERT(fixed());
1550+
SCOPE_EXIT([this] () {
1551+
collector.reset();
1552+
func.reset();
1553+
res_receiver.reset();
1554+
});
1555+
15501556
Geometry_ptr_with_buffer_and_mbr g1, g2;
15511557
uint32 srid= 0;
15521558
Gcalc_operation_transporter trn(&func, &collector);
@@ -1559,7 +1565,23 @@ String *Item_func_spatial_operation::val_str(String *str_value)
15591565
g2.construct(args[1], &tmp_value2))))
15601566
{
15611567
str_value= 0;
1562-
goto exit;
1568+
DBUG_RETURN(str_value);
1569+
}
1570+
1571+
/*
1572+
Optimization to evaluate the particular self-intersection
1573+
ST_INTERSECTION(geom, geom);
1574+
*/
1575+
if (spatial_op == Gcalc_function::op_type::op_intersection &&
1576+
*g1.geom == *g2.geom)
1577+
{
1578+
/*
1579+
Return either argument as the result, it doesn't matter which because
1580+
they're identical.
1581+
*/
1582+
String *sres= args[0]->val_str(&tmp_value1); // tmp_value1 is empty...
1583+
str_value->swap(*sres); // ...so swap the val_str result with str_value...
1584+
DBUG_RETURN(str_value); // ...to create a valid query result.
15631585
}
15641586

15651587
g1.mbr.add_mbr(&g2.mbr);
@@ -1568,33 +1590,29 @@ String *Item_func_spatial_operation::val_str(String *str_value)
15681590
if ((null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn)))
15691591
{
15701592
str_value= 0;
1571-
goto exit;
1593+
DBUG_RETURN(str_value);
15721594
}
15731595

15741596
collector.prepare_operation();
15751597
if (func.alloc_states())
1576-
goto exit;
1598+
DBUG_RETURN(str_value);
15771599

15781600
operation.init(&func);
15791601

15801602
if (operation.count_all(&collector) ||
15811603
operation.get_result(&res_receiver))
1582-
goto exit;
1604+
DBUG_RETURN(str_value);
15831605

15841606

15851607
str_value->set_charset(&my_charset_bin);
15861608
str_value->length(0);
15871609
if (str_value->reserve(SRID_SIZE, 512))
1588-
goto exit;
1610+
DBUG_RETURN(str_value);
15891611
str_value->q_append(srid);
15901612

15911613
if (!Geometry::create_from_opresult(&g1.buffer, str_value, res_receiver))
1592-
goto exit;
1614+
DBUG_RETURN(str_value);
15931615

1594-
exit:
1595-
collector.reset();
1596-
func.reset();
1597-
res_receiver.reset();
15981616
DBUG_RETURN(str_value);
15991617
}
16001618

sql/spatial.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,28 @@ int Geometry::bbox_as_json(String *wkt)
424424
}
425425

426426

427+
/**
428+
* Geometry::operator==
429+
*
430+
* @param rhs a Geometry instance to compare to *this
431+
* @return true when *this is the same Geometry as rhs, false otherwise. If
432+
* either *this or rhs have no Geometry associated (because, for
433+
* example, they are built with the default constructor) then the
434+
* comparison will always be false.
435+
*/
436+
bool Geometry::operator==(Geometry &rhs) const
437+
{
438+
if (!m_data || !rhs.m_data)
439+
return false;
440+
441+
const ptrdiff_t len= m_data_end - m_data;
442+
if (len != rhs.m_data_end - rhs.m_data)
443+
return false;
444+
445+
return memcmp(m_data, rhs.m_data, len) == 0;
446+
}
447+
448+
427449
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
428450
{
429451
double res;

sql/spatial.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ class Geometry
384384
(expected_points > ((m_data_end - data) /
385385
(POINT_DATA_SIZE + extra_point_space))));
386386
}
387+
388+
bool operator==(Geometry &rhs) const;
387389
protected:
388390
const char *m_data;
389391
const char *m_data_end;

0 commit comments

Comments
 (0)