diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-05-05 07:23:16 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-05-05 07:23:16 +0400 |
commit | 583b68e89961c35fa95a06c38988f82e33c73f4a (patch) | |
tree | d1bb1b8c7467c2bd1c08e5214dceb8c8250facaa | |
parent | aacb4d57ca5ac2dfb71bedd5b992c157b8f53b79 (diff) | |
download | mariadb-git-583b68e89961c35fa95a06c38988f82e33c73f4a.tar.gz |
MDEV-12560, MDEV-12665 - geometry type not preserved in hybrid functions and UNION
This is a join patch fixing these two bugs:
MDEV-12560 Wrong data type for SELECT NULL UNION SELECT Point(1,1)
MDEV-12665 Hybrid functions do not preserve geometry type
-rw-r--r-- | mysql-test/r/gis.result | 188 | ||||
-rw-r--r-- | mysql-test/t/gis.test | 101 | ||||
-rw-r--r-- | sql/item.cc | 12 | ||||
-rw-r--r-- | sql/item.h | 59 | ||||
-rw-r--r-- | sql/item_func.h | 5 | ||||
-rw-r--r-- | sql/sql_type.cc | 20 | ||||
-rw-r--r-- | sql/sql_type.h | 2 |
7 files changed, 366 insertions, 21 deletions
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index fdc0e1e6368..1a4a4bb48fd 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -2792,19 +2792,18 @@ t2 CREATE TABLE `t2` ( CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1 ERROR: Illegal parameter data types set and geometry for operation 'UNION' -# This does not preserve geometry type (MDEV-12560) CREATE TABLE t1 AS SELECT COALESCE(NULL, Point(1,1)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `COALESCE(NULL, Point(1,1))` geometry DEFAULT NULL + `COALESCE(NULL, Point(1,1))` point DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; CREATE TABLE t1 AS SELECT NULL UNION SELECT Point(1,1); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `NULL` geometry DEFAULT NULL + `NULL` point DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; @@ -3889,12 +3888,11 @@ Table Create Table t2 CREATE TABLE `t2` ( `LEAST(a,b)` longblob DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -# This does not preserve geometry type (MDEV-9405) CREATE TABLE t1 AS SELECT LEAST(NULL, Point(1,1)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `LEAST(NULL, Point(1,1))` geometry DEFAULT NULL + `LEAST(NULL, Point(1,1))` point DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; DROP PROCEDURE p1; @@ -4122,5 +4120,185 @@ ERROR HY000: Illegal parameter data types geometry and varchar for operation 'st SELECT STR_TO_DATE('2001-01-01', POINT(1,1)); ERROR HY000: Illegal parameter data types varchar and geometry for operation 'str_to_date' # +# MDEV-12665 Hybrid functions do not preserve geometry type +# +CREATE TABLE t1 AS SELECT +Point(0,0) AS p0, +COALESCE(Point(0,0)) AS p1, +CASE WHEN 0 THEN Point(0,0) ELSE Point(1,1) END AS p2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `p0` point DEFAULT NULL, + `p1` point DEFAULT NULL, + `p2` point DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT LEAST(Point(0,0),Point(0,0)) AS p1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `p1` point DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 ( +c_geometry GEOMETRY, +c_point POINT, +c_linestring LINESTRING, +c_polygon POLYGON, +c_multipoint MULTIPOINT, +c_multilinestring MULTILINESTRING, +c_multipolygon MULTIPOLYGON, +c_geometrycollection GEOMETRYCOLLECTION +); +CREATE TABLE t2 AS SELECT +COALESCE(NULL, c_geometry), +COALESCE(NULL, c_point), +COALESCE(NULL, c_linestring), +COALESCE(NULL, c_polygon), +COALESCE(NULL, c_multipoint), +COALESCE(NULL, c_multilinestring), +COALESCE(NULL, c_multipolygon), +COALESCE(NULL, c_geometrycollection) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(NULL, c_geometry)` geometry DEFAULT NULL, + `COALESCE(NULL, c_point)` point DEFAULT NULL, + `COALESCE(NULL, c_linestring)` linestring DEFAULT NULL, + `COALESCE(NULL, c_polygon)` polygon DEFAULT NULL, + `COALESCE(NULL, c_multipoint)` multipoint DEFAULT NULL, + `COALESCE(NULL, c_multilinestring)` multilinestring DEFAULT NULL, + `COALESCE(NULL, c_multipolygon)` multipolygon DEFAULT NULL, + `COALESCE(NULL, c_geometrycollection)` geometrycollection DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +COALESCE(c_geometry, NULL), +COALESCE(c_point, NULL), +COALESCE(c_linestring, NULL), +COALESCE(c_polygon, NULL), +COALESCE(c_multipoint, NULL), +COALESCE(c_multilinestring, NULL), +COALESCE(c_multipolygon, NULL), +COALESCE(c_geometrycollection, NULL) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(c_geometry, NULL)` geometry DEFAULT NULL, + `COALESCE(c_point, NULL)` point DEFAULT NULL, + `COALESCE(c_linestring, NULL)` linestring DEFAULT NULL, + `COALESCE(c_polygon, NULL)` polygon DEFAULT NULL, + `COALESCE(c_multipoint, NULL)` multipoint DEFAULT NULL, + `COALESCE(c_multilinestring, NULL)` multilinestring DEFAULT NULL, + `COALESCE(c_multipolygon, NULL)` multipolygon DEFAULT NULL, + `COALESCE(c_geometrycollection, NULL)` geometrycollection DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +COALESCE(c_geometry, c_geometry), +COALESCE(c_point, c_point), +COALESCE(c_linestring, c_linestring), +COALESCE(c_polygon, c_polygon), +COALESCE(c_multipoint, c_multipoint), +COALESCE(c_multilinestring, c_multilinestring), +COALESCE(c_multipolygon, c_multipolygon), +COALESCE(c_geometrycollection, c_geometrycollection) +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `COALESCE(c_geometry, c_geometry)` geometry DEFAULT NULL, + `COALESCE(c_point, c_point)` point DEFAULT NULL, + `COALESCE(c_linestring, c_linestring)` linestring DEFAULT NULL, + `COALESCE(c_polygon, c_polygon)` polygon DEFAULT NULL, + `COALESCE(c_multipoint, c_multipoint)` multipoint DEFAULT NULL, + `COALESCE(c_multilinestring, c_multilinestring)` multilinestring DEFAULT NULL, + `COALESCE(c_multipolygon, c_multipolygon)` multipolygon DEFAULT NULL, + `COALESCE(c_geometrycollection, c_geometrycollection)` geometrycollection DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2; +DROP TABLE t1; +# +# MDEV-12560 Wrong data type for SELECT NULL UNION SELECT Point(1,1) +# +CREATE TABLE t1 AS SELECT NULL AS c1 UNION SELECT POINT(1,1); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` point DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE PROCEDURE p1(name TEXT) +BEGIN +EXECUTE IMMEDIATE CONCAT('CREATE TABLE t1 (a ', name, ')'); +CREATE TABLE t2 AS +SELECT a AS a1, a AS a2, NULL AS a3 FROM t1 UNION +SELECT a AS a1, NULL AS a2, a AS a3 FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; +DROP TABLE t1; +END; +$$ +CALL p1('geometry'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` geometry DEFAULT NULL, + `a2` geometry DEFAULT NULL, + `a3` geometry DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('point'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` point DEFAULT NULL, + `a2` point DEFAULT NULL, + `a3` point DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('linestring'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` linestring DEFAULT NULL, + `a2` linestring DEFAULT NULL, + `a3` linestring DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('polygon'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` polygon DEFAULT NULL, + `a2` polygon DEFAULT NULL, + `a3` polygon DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('multipoint'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` multipoint DEFAULT NULL, + `a2` multipoint DEFAULT NULL, + `a3` multipoint DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('multilinestring'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` multilinestring DEFAULT NULL, + `a2` multilinestring DEFAULT NULL, + `a3` multilinestring DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('multipolygon'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` multipolygon DEFAULT NULL, + `a2` multipolygon DEFAULT NULL, + `a3` multipolygon DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CALL p1('geometrycollection'); +Table Create Table +t2 CREATE TABLE `t2` ( + `a1` geometrycollection DEFAULT NULL, + `a2` geometrycollection DEFAULT NULL, + `a3` geometrycollection DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP PROCEDURE p1; +# # End of 10.3 tests # diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 9b3dc69a7d1..34797337b1d 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -1789,7 +1789,6 @@ CALL p1('CREATE TABLE t1 (a ENUM(0x61), b Point)'); CALL p1('CREATE TABLE t1 (a SET(0x61), b Point)'); --enable_query_log ---echo # This does not preserve geometry type (MDEV-12560) CREATE TABLE t1 AS SELECT COALESCE(NULL, Point(1,1)); SHOW CREATE TABLE t1; DROP TABLE t1; @@ -1932,7 +1931,6 @@ CALL p1('CREATE TABLE t1 (a ENUM(0x61), b Point)'); CALL p1('CREATE TABLE t1 (a SET(0x61), b Point)'); --enable_query_log ---echo # This does not preserve geometry type (MDEV-9405) CREATE TABLE t1 AS SELECT LEAST(NULL, Point(1,1)); SHOW CREATE TABLE t1; DROP TABLE t1; @@ -2197,5 +2195,104 @@ SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y'); SELECT STR_TO_DATE('2001-01-01', POINT(1,1)); --echo # +--echo # MDEV-12665 Hybrid functions do not preserve geometry type +--echo # + +CREATE TABLE t1 AS SELECT + Point(0,0) AS p0, + COALESCE(Point(0,0)) AS p1, + CASE WHEN 0 THEN Point(0,0) ELSE Point(1,1) END AS p2; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT LEAST(Point(0,0),Point(0,0)) AS p1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 ( + c_geometry GEOMETRY, + c_point POINT, + c_linestring LINESTRING, + c_polygon POLYGON, + c_multipoint MULTIPOINT, + c_multilinestring MULTILINESTRING, + c_multipolygon MULTIPOLYGON, + c_geometrycollection GEOMETRYCOLLECTION +); + +CREATE TABLE t2 AS SELECT + COALESCE(NULL, c_geometry), + COALESCE(NULL, c_point), + COALESCE(NULL, c_linestring), + COALESCE(NULL, c_polygon), + COALESCE(NULL, c_multipoint), + COALESCE(NULL, c_multilinestring), + COALESCE(NULL, c_multipolygon), + COALESCE(NULL, c_geometrycollection) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + COALESCE(c_geometry, NULL), + COALESCE(c_point, NULL), + COALESCE(c_linestring, NULL), + COALESCE(c_polygon, NULL), + COALESCE(c_multipoint, NULL), + COALESCE(c_multilinestring, NULL), + COALESCE(c_multipolygon, NULL), + COALESCE(c_geometrycollection, NULL) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + COALESCE(c_geometry, c_geometry), + COALESCE(c_point, c_point), + COALESCE(c_linestring, c_linestring), + COALESCE(c_polygon, c_polygon), + COALESCE(c_multipoint, c_multipoint), + COALESCE(c_multilinestring, c_multilinestring), + COALESCE(c_multipolygon, c_multipolygon), + COALESCE(c_geometrycollection, c_geometrycollection) +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +DROP TABLE t1; + + +--echo # +--echo # MDEV-12560 Wrong data type for SELECT NULL UNION SELECT Point(1,1) +--echo # + +CREATE TABLE t1 AS SELECT NULL AS c1 UNION SELECT POINT(1,1); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +DELIMITER $$; +CREATE PROCEDURE p1(name TEXT) +BEGIN + EXECUTE IMMEDIATE CONCAT('CREATE TABLE t1 (a ', name, ')'); + CREATE TABLE t2 AS + SELECT a AS a1, a AS a2, NULL AS a3 FROM t1 UNION + SELECT a AS a1, NULL AS a2, a AS a3 FROM t1; + SHOW CREATE TABLE t2; + DROP TABLE t2; + DROP TABLE t1; +END; +$$ +DELIMITER ;$$ +CALL p1('geometry'); +CALL p1('point'); +CALL p1('linestring'); +CALL p1('polygon'); +CALL p1('multipoint'); +CALL p1('multilinestring'); +CALL p1('multipolygon'); +CALL p1('geometrycollection'); +DROP PROCEDURE p1; + +--echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index 870b2449514..bf962777a48 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9913,18 +9913,14 @@ void Item_cache_row::set_null() Item_type_holder::Item_type_holder(THD *thd, Item *item) :Item(thd, item), Type_handler_hybrid_field_type(item->real_type_handler()), - enum_set_typelib(0), - geometry_type(Field::GEOM_GEOMETRY) + Type_geometry_attributes(item), + enum_set_typelib(0) { DBUG_ASSERT(item->fixed); maybe_null= item->maybe_null; get_full_info(item); DBUG_ASSERT(!decimals || Item_type_holder::result_type() != INT_RESULT); prev_decimal_int_part= item->decimal_int_part(); -#ifdef HAVE_SPATIAL - if (item->field_type() == MYSQL_TYPE_GEOMETRY) - geometry_type= item->get_geometry_type(); -#endif /* HAVE_SPATIAL */ } @@ -9977,9 +9973,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) else decimals= MY_MAX(decimals, item->decimals); - if (Item_type_holder::field_type() == FIELD_TYPE_GEOMETRY) - geometry_type= - Field_geom::geometry_type_merge(geometry_type, item->get_geometry_type()); + Type_geometry_attributes::join(item); if (Item_type_holder::result_type() == DECIMAL_RESULT) { diff --git a/sql/item.h b/sql/item.h index 241fc0e6398..5b85664bf73 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1825,6 +1825,55 @@ inline Item* get_item_copy (THD *thd, MEM_ROOT *mem_root, T* item) } +class Type_geometry_attributes +{ + uint m_geometry_type; + static const uint m_geometry_type_unknown= Field::GEOM_GEOMETRYCOLLECTION + 1; + void copy(const Item *item) + { + // Ignore implicit NULLs + m_geometry_type= item->type_handler() == &type_handler_geometry ? + item->uint_geometry_type() : + m_geometry_type_unknown; + } +public: + Type_geometry_attributes() + :m_geometry_type(m_geometry_type_unknown) + { } + Type_geometry_attributes(const Item *item) + :m_geometry_type(m_geometry_type_unknown) + { + copy(item); + } + void join(const Item *item) + { + // Ignore implicit NULLs + if (m_geometry_type == m_geometry_type_unknown) + copy(item); + else if (item->type_handler() == &type_handler_geometry) + { + m_geometry_type= + Field_geom::geometry_type_merge((Field_geom::geometry_type) + m_geometry_type, + (Field_geom::geometry_type) + item->uint_geometry_type()); + } + } + Field::geometry_type get_geometry_type() const + { + return m_geometry_type == m_geometry_type_unknown ? + Field::GEOM_GEOMETRY : + (Field::geometry_type) m_geometry_type; + } + void set_geometry_type(uint type) + { + DBUG_ASSERT(type <= m_geometry_type_unknown); + m_geometry_type= type; + } +}; + + + /** Compare two Items for List<Item>::add_unique() */ @@ -5796,12 +5845,11 @@ public: single SP/PS execution. */ class Item_type_holder: public Item, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Type_geometry_attributes { protected: TYPELIB *enum_set_typelib; - Field::geometry_type geometry_type; - void get_full_info(Item *item); /* It is used to count decimal precision in join_types */ @@ -5850,7 +5898,10 @@ public: make_and_init_table_field(&name, Record_addr(maybe_null), *this, table); } - Field::geometry_type get_geometry_type() const { return geometry_type; }; + Field::geometry_type get_geometry_type() const + { + return Type_geometry_attributes::get_geometry_type(); + } Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; diff --git a/sql/item_func.h b/sql/item_func.h index 4b47c7b1f95..33726cd2d84 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -381,7 +381,8 @@ public: Functions whose returned field type is determined at fix_fields() time. */ class Item_hybrid_func: public Item_func, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type, + public Type_geometry_attributes { protected: bool fix_attributes(Item **item, uint nitems); @@ -402,6 +403,8 @@ public: { return Type_handler_hybrid_field_type::result_type(); } enum Item_result cmp_type () const { return Type_handler_hybrid_field_type::cmp_type(); } + Field::geometry_type get_geometry_type() const + { return Type_geometry_attributes::get_geometry_type(); }; }; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index f52d09cd669..abf0b77481e 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -2148,6 +2148,26 @@ bool Type_handler_timestamp_common:: return false; } +#ifdef HAVE_SPATIAL +bool Type_handler_geometry:: + Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const +{ + DBUG_ASSERT(nitems > 0); + Type_geometry_attributes gattr(items[0]); + for (uint i= 1; i < nitems; i++) + gattr.join(items[i]); + func->set_geometry_type(gattr.get_geometry_type()); + func->collation.set(&my_charset_bin); + func->unsigned_flag= false; + func->decimals= 0; + func->max_length= (uint32) UINT_MAX32; + func->maybe_null= true; + return false; +} +#endif + + /*************************************************************************/ bool Type_handler:: diff --git a/sql/sql_type.h b/sql/sql_type.h index b94d73e8d23..b4564b293dd 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -2153,6 +2153,8 @@ public: bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const; bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const; bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const; + bool Item_hybrid_func_fix_attributes(THD *thd, Item_hybrid_func *func, + Item **items, uint nitems) const; bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const; bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const; bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const; |