Commit 583b68e8 authored by Alexander Barkov's avatar Alexander Barkov

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
parent aacb4d57
......@@ -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
#
......@@ -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;
......@@ -2196,6 +2194,105 @@ SELECT STR_TO_DATE(POINT(1,1),'%M %d,%Y');
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
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 #
......@@ -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)
{
......
......@@ -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 @@ class Item_cache_row: public Item_cache
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 @@ class Item_type_holder: public Item,
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; }
};
......
......@@ -381,7 +381,8 @@ class Item_real_func :public Item_func
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 @@ class Item_hybrid_func: public Item_func,
{ 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(); };
};
......
......@@ -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::
......
......@@ -2153,6 +2153,8 @@ class Type_handler_geometry: public Type_handler_string_result
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;
......
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