Commit aec287fd authored by unknown's avatar unknown

Bug #30825: Problems when putting a non-spatial index on a GIS column

 Fixed the usage of spatial data (and Point in specific) with 
 non-spatial indexes.
 Several problems :
   - The length of the Point class was not updated to include the 
     spatial reference system identifier. Fixed by increasing with 4 
     bytes.
   - The storage length of the spatial columns was not accounting for
     the length that is prepended to it. Fixed by treating the 
     spatial data columns as blobs (and thus increasing the storage
     length)
   - When creating the key image for comparison in index read wrong
     key image was created (the one needed for and r-tree search,
     not the one for b-tree/other search). Fixed by treating the
     spatial data columns as blobs (and creating the correct kind of
     image based on the index type). 


mysql-test/r/bdb_gis.result:
  Bug #30825: bdb tests
mysql-test/r/gis-rtree.result:
  Bug #30825: key length changed
mysql-test/r/gis.result:
  Bug #30825: MyISAM tests
mysql-test/r/innodb_gis.result:
  Bug #30825: InnoDB tests
mysql-test/t/bdb_gis.test:
  Bug #30825: bdb tests
mysql-test/t/gis.test:
  Bug #30825: MyISAM tests
mysql-test/t/innodb_gis.test:
  Bug #30825: InnoDB tests
sql/field.cc:
  Bug #30825: Removed Field_geom::get_key_image as Field_blog::get_key_image 
    takes type parameter into consideration and is a superset of 
    Field_geom::get_key_image()
sql/field.h:
  Bug #30825: Removed Field_geom::get_key_image as Field_blog::get_key_image 
    takes type parameter into consideration and is a superset of 
    Field_geom::get_key_image()
sql/sql_select.h:
  Bug #30825: Geometry data are a blob derivate
sql/sql_table.cc:
  Bug #30825: Increased key length to accomodate for
    spatial reference system identifier (srid)
sql/sql_yacc.yy:
  Bug #30825: Increased key length to accomodate for
    spatial reference system identifier (srid)
sql/table.cc:
  Bug #30825: It stores a length for spatial data
   as well, so increase the storage length (as it's
   done for blobs).
mysql-test/include/gis_keys.inc:
  Bug #30825: Test file for spatial data and non-spatial indexes
parent 6146c0c7
--source include/have_geometry.inc
#
# Spatial objects with keys
#
#
# Bug #30825: Problems when putting a non-spatial index on a GIS column
#
CREATE TABLE t1 (p POINT);
CREATE TABLE t2 (p POINT, INDEX(p));
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
-- no index, returns 1 as expected
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
-- with index, returns 1 as expected
-- EXPLAIN shows that the index is not used though
-- due to the "most rows covered anyway, so a scan is more effective" rule
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
-- adding another row to the table so that
-- the "most rows covered" rule doesn't kick in anymore
-- now EXPLAIN shows the index used on the table
-- and we're getting the wrong result again
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
EXPLAIN
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
EXPLAIN
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
DROP TABLE t1, t2;
--echo End of 5.0 tests
...@@ -542,3 +542,42 @@ Overlaps(@horiz1, @point2) ...@@ -542,3 +542,42 @@ Overlaps(@horiz1, @point2)
0 0
DROP TABLE t1; DROP TABLE t1;
End of 5.0 tests End of 5.0 tests
CREATE TABLE t1 (p POINT);
CREATE TABLE t2 (p POINT, INDEX(p));
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref p p 28 const 1 Using where
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
EXPLAIN
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL p NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
...@@ -167,7 +167,7 @@ count(*) ...@@ -167,7 +167,7 @@ count(*)
150 150
EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range g g 32 NULL 8 Using where 1 SIMPLE t1 range g g 34 NULL 8 Using where
SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))'));
fid AsText(g) fid AsText(g)
1 LINESTRING(150 150,150 150) 1 LINESTRING(150 150,150 150)
...@@ -301,7 +301,7 @@ count(*) ...@@ -301,7 +301,7 @@ count(*)
EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g, EXPLAIN SELECT fid, AsText(g) FROM t2 WHERE Within(g,
GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range g g 32 NULL 4 Using where 1 SIMPLE t2 range g g 34 NULL 4 Using where
SELECT fid, AsText(g) FROM t2 WHERE Within(g, SELECT fid, AsText(g) FROM t2 WHERE Within(g,
GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
fid AsText(g) fid AsText(g)
......
...@@ -894,4 +894,43 @@ drop table t1, t2; ...@@ -894,4 +894,43 @@ drop table t1, t2;
SELECT 1; SELECT 1;
1 1
1 1
CREATE TABLE t1 (p POINT);
CREATE TABLE t2 (p POINT, INDEX(p));
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 system p NULL NULL NULL 1
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
EXPLAIN
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref p p 28 const 1 Using where
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
End of 5.0 tests End of 5.0 tests
...@@ -542,3 +542,42 @@ Overlaps(@horiz1, @point2) ...@@ -542,3 +542,42 @@ Overlaps(@horiz1, @point2)
0 0
DROP TABLE t1; DROP TABLE t1;
End of 5.0 tests End of 5.0 tests
CREATE TABLE t1 (p POINT);
CREATE TABLE t2 (p POINT, INDEX(p));
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref p p 28 const 1 Using where
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
1
INSERT INTO t1 VALUES (POINTFROMTEXT('POINT(1 2)'));
INSERT INTO t2 VALUES (POINTFROMTEXT('POINT(1 2)'));
EXPLAIN
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t1 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref p p 28 const 1 Using where
SELECT COUNT(*) FROM t2 WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
EXPLAIN
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using where
SELECT COUNT(*) FROM t2 IGNORE INDEX(p) WHERE p=POINTFROMTEXT('POINT(1 2)');
COUNT(*)
2
DROP TABLE t1, t2;
End of 5.0 tests
-- source include/have_bdb.inc -- source include/have_bdb.inc
SET storage_engine=bdb; SET storage_engine=bdb;
--source include/gis_generic.inc --source include/gis_generic.inc
--source include/gis_keys.inc
...@@ -598,4 +598,6 @@ SELECT AsText(GeometryFromText(CONCAT( ...@@ -598,4 +598,6 @@ SELECT AsText(GeometryFromText(CONCAT(
--enable_query_log --enable_query_log
SELECT 1; SELECT 1;
-- source include/gis_keys.inc
--echo End of 5.0 tests --echo End of 5.0 tests
--source include/have_innodb.inc --source include/have_innodb.inc
SET storage_engine=innodb; SET storage_engine=innodb;
--source include/gis_generic.inc --source include/gis_generic.inc
--source include/gis_keys.inc
...@@ -7416,36 +7416,6 @@ uint Field_blob::max_packed_col_length(uint max_length) ...@@ -7416,36 +7416,6 @@ uint Field_blob::max_packed_col_length(uint max_length)
#ifdef HAVE_SPATIAL #ifdef HAVE_SPATIAL
uint Field_geom::get_key_image(char *buff, uint length, imagetype type)
{
char *blob;
const char *dummy;
MBR mbr;
ulong blob_length= get_length(ptr);
Geometry_buffer buffer;
Geometry *gobj;
const uint image_length= SIZEOF_STORED_DOUBLE*4;
if (blob_length < SRID_SIZE)
{
bzero(buff, image_length);
return image_length;
}
get_ptr(&blob);
gobj= Geometry::construct(&buffer, blob, blob_length);
if (!gobj || gobj->get_mbr(&mbr, &dummy))
bzero(buff, image_length);
else
{
float8store(buff, mbr.xmin);
float8store(buff + 8, mbr.xmax);
float8store(buff + 16, mbr.ymin);
float8store(buff + 24, mbr.ymax);
}
return image_length;
}
void Field_geom::sql_type(String &res) const void Field_geom::sql_type(String &res) const
{ {
CHARSET_INFO *cs= &my_charset_latin1; CHARSET_INFO *cs= &my_charset_latin1;
......
...@@ -1326,7 +1326,6 @@ public: ...@@ -1326,7 +1326,6 @@ public:
int store(double nr); int store(double nr);
int store(longlong nr, bool unsigned_val); int store(longlong nr, bool unsigned_val);
int store_decimal(const my_decimal *); int store_decimal(const my_decimal *);
uint get_key_image(char *buff,uint length,imagetype type);
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
int reset(void) { return !maybe_null() || Field_blob::reset(); } int reset(void) { return !maybe_null() || Field_blob::reset(); }
geometry_type get_geometry_type() { return geom_type; }; geometry_type get_geometry_type() { return geom_type; };
......
...@@ -521,9 +521,13 @@ public: ...@@ -521,9 +521,13 @@ public:
store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length) store_key(THD *thd, Field *field_arg, char *ptr, char *null, uint length)
:null_key(0), null_ptr(null), err(0) :null_key(0), null_ptr(null), err(0)
{ {
if (field_arg->type() == FIELD_TYPE_BLOB) if (field_arg->type() == FIELD_TYPE_BLOB
|| field_arg->type() == FIELD_TYPE_GEOMETRY)
{ {
/* Key segments are always packed with a 2 byte length prefix */ /*
Key segments are always packed with a 2 byte length prefix.
See mi_rkey for details.
*/
to_field=new Field_varstring(ptr, length, 2, (uchar*) null, 1, to_field=new Field_varstring(ptr, length, 2, (uchar*) null, 1,
Field::NONE, field_arg->field_name, Field::NONE, field_arg->field_name,
field_arg->table, field_arg->charset()); field_arg->table, field_arg->charset());
......
...@@ -1287,7 +1287,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1287,7 +1287,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
} }
if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type == if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
Field::GEOM_POINT) Field::GEOM_POINT)
column->length= 21; column->length= 25;
if (!column->length) if (!column->length)
{ {
my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name); my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name);
......
...@@ -3216,7 +3216,7 @@ type: ...@@ -3216,7 +3216,7 @@ type:
spatial_type: spatial_type:
GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; } GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
| GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; } | GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
| POINT_SYM { Lex->length= (char*)"21"; | POINT_SYM { Lex->length= (char*)"25";
$$= Field::GEOM_POINT; $$= Field::GEOM_POINT;
} }
| MULTIPOINT { $$= Field::GEOM_MULTIPOINT; } | MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
......
...@@ -732,9 +732,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ...@@ -732,9 +732,11 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
keyinfo->key_length+= HA_KEY_NULL_LENGTH; keyinfo->key_length+= HA_KEY_NULL_LENGTH;
} }
if (field->type() == FIELD_TYPE_BLOB || if (field->type() == FIELD_TYPE_BLOB ||
field->real_type() == MYSQL_TYPE_VARCHAR) field->real_type() == MYSQL_TYPE_VARCHAR ||
field->type() == FIELD_TYPE_GEOMETRY)
{ {
if (field->type() == FIELD_TYPE_BLOB) if (field->type() == FIELD_TYPE_BLOB ||
field->type() == FIELD_TYPE_GEOMETRY)
key_part->key_part_flag|= HA_BLOB_PART; key_part->key_part_flag|= HA_BLOB_PART;
else else
key_part->key_part_flag|= HA_VAR_LENGTH_PART; key_part->key_part_flag|= HA_VAR_LENGTH_PART;
......
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