Skip to content

Commit 649b29e

Browse files
committed
Bug#21067378 GEOMETRIC OPERATION RETURNS ERROR INSTEAD OF RESULT
Problem: A query on a geometry column will return an error instead of a result if there exists a UNIQUE index on the column. The range optimizer temporarily transforms geometry columns of specific subtypes to generic geometry columns while using the field for type transformation. This only happens if the column is of type MYSQL_TYPE_GEOMETRY and key_part->image_type is Field::itMBR. However, when there's a spatial index on the column, key_part->image_type is Field::itRAW, and the column type is not changed to the geometry supertype. When a value is inserted that doesn't match the subtype, an error is flagged and the query is aborted. When the error is avoided, the result is still wrong since the predicate is not recognized as a spatial operator. Fix: Temporarily change all geometry columns to the geometry supertype, regardless of image_type. Add COVERS and COVEREDBY to the list in is_spatial_operator().
1 parent f374e86 commit 649b29e

File tree

4 files changed

+78
-19
lines changed

4 files changed

+78
-19
lines changed

mysql-test/r/gis.result

+25
Original file line numberDiff line numberDiff line change
@@ -2212,3 +2212,28 @@ Note 1003 /* select#1 */ select st_astext(`test`.`t1`.`p`) AS `ST_AsText(p)` fro
22122212
SELECT ST_AsText(p) FROM t1 WHERE ST_Equals(p, ST_PointFromText('POINT(20 20)'));
22132213
ST_AsText(p)
22142214
DROP TABLE t1;
2215+
#
2216+
# Bug #21067378 GEOMETRIC OPERATION RETURNS ERROR INSTEAD OF RESULT
2217+
#
2218+
CREATE TABLE t1 (p POINT NOT NULL UNIQUE) ENGINE=InnoDB;
2219+
INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('POINT(1 1)'));
2220+
SELECT ST_ASTEXT(p) FROM t1
2221+
WHERE MBRCOVEREDBY
2222+
(
2223+
p,
2224+
ST_GEOMFROMTEXT('POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))')
2225+
);
2226+
ST_ASTEXT(p)
2227+
POINT(1 1)
2228+
DROP TABLE t1;
2229+
CREATE TABLE t1 (p POINT NOT NULL UNIQUE) ENGINE=MyISAM;
2230+
INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('POINT(1 1)'));
2231+
SELECT ST_ASTEXT(p) FROM t1
2232+
WHERE MBRCOVEREDBY
2233+
(
2234+
p,
2235+
ST_GEOMFROMTEXT('POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))')
2236+
);
2237+
ST_ASTEXT(p)
2238+
POINT(1 1)
2239+
DROP TABLE t1;

mysql-test/t/gis.test

+30
Original file line numberDiff line numberDiff line change
@@ -2240,3 +2240,33 @@ EXPLAIN SELECT ST_AsText(p) FROM t1 WHERE ST_Equals(p, ST_PointFromText('POINT(2
22402240
SELECT ST_AsText(p) FROM t1 WHERE ST_Equals(p, ST_PointFromText('POINT(20 20)'));
22412241

22422242
DROP TABLE t1;
2243+
2244+
--echo #
2245+
--echo # Bug #21067378 GEOMETRIC OPERATION RETURNS ERROR INSTEAD OF RESULT
2246+
--echo #
2247+
2248+
CREATE TABLE t1 (p POINT NOT NULL UNIQUE) ENGINE=InnoDB;
2249+
2250+
INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('POINT(1 1)'));
2251+
2252+
SELECT ST_ASTEXT(p) FROM t1
2253+
WHERE MBRCOVEREDBY
2254+
(
2255+
p,
2256+
ST_GEOMFROMTEXT('POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))')
2257+
);
2258+
2259+
DROP TABLE t1;
2260+
2261+
CREATE TABLE t1 (p POINT NOT NULL UNIQUE) ENGINE=MyISAM;
2262+
2263+
INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('POINT(1 1)'));
2264+
2265+
SELECT ST_ASTEXT(p) FROM t1
2266+
WHERE MBRCOVEREDBY
2267+
(
2268+
p,
2269+
ST_GEOMFROMTEXT('POLYGON((1 1, 1 2, 2 2, 2 1, 1 1))')
2270+
);
2271+
2272+
DROP TABLE t1;

sql/item_func.h

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class Item_func :public Item_result_field
4949
public:
5050
uint arg_count;
5151
//bool const_item_cache;
52+
// When updating Functype with new spatial functions,
53+
// is_spatial_operator() should also be updated.
5254
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
5355
GE_FUNC,GT_FUNC,FT_FUNC,
5456
LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,

sql/opt_range.cc

+21-19
Original file line numberDiff line numberDiff line change
@@ -6757,6 +6757,8 @@ bool is_spatial_operator(Item_func::Functype op_type)
67576757
case Item_func::SP_CROSSES_FUNC:
67586758
case Item_func::SP_WITHIN_FUNC:
67596759
case Item_func::SP_CONTAINS_FUNC:
6760+
case Item_func::SP_COVEREDBY_FUNC:
6761+
case Item_func::SP_COVERS_FUNC:
67606762
case Item_func::SP_OVERLAPS_FUNC:
67616763
case Item_func::SP_STARTPOINT:
67626764
case Item_func::SP_ENDPOINT:
@@ -7328,29 +7330,29 @@ get_mm_leaf(RANGE_OPT_PARAM *param, Item *conf_func, Field *field,
73287330
set the most general geometry type while saving, and revert to the
73297331
original geometry type afterwards.
73307332
*/
7331-
Field::geometry_type save_geom_type;
7332-
save_geom_type= Field::GEOM_GEOMETRY;
7333-
if (key_part->image_type == Field::itMBR &&
7334-
field->type() == MYSQL_TYPE_GEOMETRY)
73357333
{
7336-
save_geom_type= field->get_geometry_type();
7337-
down_cast<Field_geom*, Field*>(field)->geom_type= Field::GEOM_GEOMETRY;
7338-
}
7334+
const Field::geometry_type save_geom_type=
7335+
(field->type() == MYSQL_TYPE_GEOMETRY) ?
7336+
field->get_geometry_type() :
7337+
Field::GEOM_GEOMETRY;
7338+
if (field->type() == MYSQL_TYPE_GEOMETRY)
7339+
{
7340+
down_cast<Field_geom*>(field)->geom_type= Field::GEOM_GEOMETRY;
7341+
}
73397342

7340-
bool always_true_or_false;
7341-
always_true_or_false=
7342-
save_value_and_handle_conversion(&tree, value, type, field,
7343-
&impossible_cond_cause, alloc);
7343+
bool always_true_or_false=
7344+
save_value_and_handle_conversion(&tree, value, type, field,
7345+
&impossible_cond_cause, alloc);
73447346

7345-
if (key_part->image_type == Field::itMBR &&
7346-
field->type() == MYSQL_TYPE_GEOMETRY &&
7347-
save_geom_type != Field::GEOM_GEOMETRY)
7348-
{
7349-
down_cast<Field_geom*, Field*>(field)->geom_type= save_geom_type;
7347+
if (field->type() == MYSQL_TYPE_GEOMETRY &&
7348+
save_geom_type != Field::GEOM_GEOMETRY)
7349+
{
7350+
down_cast<Field_geom*>(field)->geom_type= save_geom_type;
7351+
}
7352+
7353+
if (always_true_or_false)
7354+
goto end;
73507355
}
7351-
7352-
if (always_true_or_false)
7353-
goto end;
73547356

73557357
/*
73567358
Any sargable predicate except "<=>" involving NULL as a constant is always

0 commit comments

Comments
 (0)