Commit cbb38476 authored by unknown's avatar unknown
Browse files

Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL

Having maybe_null flag unset for geometry/spatial functions leads to
wrong Item_func_isnull::val_int()'s results.
Fix: set maybe_null flag and add is_null() methods.


mysql-test/r/gis.result:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - test result.
mysql-test/t/gis.test:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - test case.
sql/item_geofunc.cc:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - set maybe_null flag for Item_geometry_func and Item_func_as_wkt.
    - moved length check to the beginnig of the 
      Item_func_spatial_collection::val_str() to affect geometry 
      collection objects at once.
    - changed Item_func_isempty::val_int() and Item_func_issimple::val_int()
      to properly handle null_value.
sql/item_geofunc.h:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - set maybe_null flag for geometry/spatial functions.
    - added is_null() to Item_geometry_func and Item_func_spatial_rel
      classes.
sql/spatial.cc:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - changed return type of Geometry::create_from_wkb() to be 
      consistent with Geometry::create_from_wkt(), now it returns
      Geometry object or NULL in case of error.
sql/spatial.h:
  Fix for bug #26038: X() value of empty NOT NULL POINT is neither NULL nor NOT NULL
    - changed return type of Geometry::create_from_wkb() to be 
      consistent with Geometry::create_from_wkt(), now it returns
      Geometry object or NULL in case of error.
parent 557f6169
Loading
Loading
Loading
Loading
+43 −1
Original line number Diff line number Diff line
@@ -578,7 +578,7 @@ create table t1 select POINT(1,3);
show create table t1;
Table	Create Table
t1	CREATE TABLE `t1` (
  `POINT(1,3)` longblob NOT NULL
  `POINT(1,3)` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
CREATE TABLE `t1` (`object_id` bigint(20) unsigned NOT NULL default '0', `geo`
@@ -677,3 +677,45 @@ load data infile '../../std_data/bad_gis_data.dat' into table t1;
ERROR 01000: Data truncated; NULL supplied to NOT NULL column 'b' at row 1
alter table t1 enable keys;
drop table t1;
create table t1 (a int, b blob);
insert into t1 values (1, ''), (2, NULL), (3, '1');
select * from t1;
a	b
1	
2	NULL
3	1
select
geometryfromtext(b) IS NULL, geometryfromwkb(b) IS NULL, astext(b) IS NULL, 
aswkb(b) IS NULL, geometrytype(b) IS NULL, centroid(b) IS NULL,
envelope(b) IS NULL, startpoint(b) IS NULL, endpoint(b) IS NULL,
exteriorring(b) IS NULL, pointn(b, 1) IS NULL, geometryn(b, 1) IS NULL,
interiorringn(b, 1) IS NULL, multipoint(b) IS NULL, isempty(b) IS NULL,
issimple(b) IS NULL, isclosed(b) IS NULL, dimension(b) IS NULL,
numgeometries(b) IS NULL, numinteriorrings(b) IS NULL, numpoints(b) IS NULL,
area(b) IS NULL, glength(b) IS NULL, srid(b) IS NULL, x(b) IS NULL, 
y(b) IS NULL
from t1;
geometryfromtext(b) IS NULL	geometryfromwkb(b) IS NULL	astext(b) IS NULL	aswkb(b) IS NULL	geometrytype(b) IS NULL	centroid(b) IS NULL	envelope(b) IS NULL	startpoint(b) IS NULL	endpoint(b) IS NULL	exteriorring(b) IS NULL	pointn(b, 1) IS NULL	geometryn(b, 1) IS NULL	interiorringn(b, 1) IS NULL	multipoint(b) IS NULL	isempty(b) IS NULL	issimple(b) IS NULL	isclosed(b) IS NULL	dimension(b) IS NULL	numgeometries(b) IS NULL	numinteriorrings(b) IS NULL	numpoints(b) IS NULL	area(b) IS NULL	glength(b) IS NULL	srid(b) IS NULL	x(b) IS NULL	y(b) IS NULL
1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1	1
select 
within(b, b) IS NULL, contains(b, b) IS NULL, overlaps(b, b) IS NULL, 
equals(b, b) IS NULL, disjoint(b, b) IS NULL, touches(b, b) IS NULL, 
intersects(b, b) IS NULL, crosses(b, b) IS NULL
from t1;
within(b, b) IS NULL	contains(b, b) IS NULL	overlaps(b, b) IS NULL	equals(b, b) IS NULL	disjoint(b, b) IS NULL	touches(b, b) IS NULL	intersects(b, b) IS NULL	crosses(b, b) IS NULL
1	1	1	1	1	1	1	1
1	1	1	1	1	1	1	1
1	1	1	1	1	1	1	1
select 
point(b, b) IS NULL, linestring(b) IS NULL, polygon(b) IS NULL, multipoint(b) IS NULL, 
multilinestring(b) IS NULL, multipolygon(b) IS NULL, 
geometrycollection(b) IS NULL
from t1;
point(b, b) IS NULL	linestring(b) IS NULL	polygon(b) IS NULL	multipoint(b) IS NULL	multilinestring(b) IS NULL	multipolygon(b) IS NULL	geometrycollection(b) IS NULL
0	1	1	1	1	1	1
1	1	1	1	1	1	1
0	1	1	1	1	1	1
drop table t1;
End of 4.1 tests
+35 −1
Original line number Diff line number Diff line
@@ -377,4 +377,38 @@ load data infile '../../std_data/bad_gis_data.dat' into table t1;
alter table t1 enable keys;
drop table t1;

# End of 4.1 tests
#
# Bug #26038: is null and bad data
#

create table t1 (a int, b blob);
insert into t1 values (1, ''), (2, NULL), (3, '1');
select * from t1;

select
  geometryfromtext(b) IS NULL, geometryfromwkb(b) IS NULL, astext(b) IS NULL, 
  aswkb(b) IS NULL, geometrytype(b) IS NULL, centroid(b) IS NULL,
  envelope(b) IS NULL, startpoint(b) IS NULL, endpoint(b) IS NULL,
  exteriorring(b) IS NULL, pointn(b, 1) IS NULL, geometryn(b, 1) IS NULL,
  interiorringn(b, 1) IS NULL, multipoint(b) IS NULL, isempty(b) IS NULL,
  issimple(b) IS NULL, isclosed(b) IS NULL, dimension(b) IS NULL,
  numgeometries(b) IS NULL, numinteriorrings(b) IS NULL, numpoints(b) IS NULL,
  area(b) IS NULL, glength(b) IS NULL, srid(b) IS NULL, x(b) IS NULL, 
  y(b) IS NULL
from t1;

select 
  within(b, b) IS NULL, contains(b, b) IS NULL, overlaps(b, b) IS NULL, 
  equals(b, b) IS NULL, disjoint(b, b) IS NULL, touches(b, b) IS NULL, 
  intersects(b, b) IS NULL, crosses(b, b) IS NULL
from t1;

select 
  point(b, b) IS NULL, linestring(b) IS NULL, polygon(b) IS NULL, multipoint(b) IS NULL, 
  multilinestring(b) IS NULL, multipolygon(b) IS NULL, 
  geometrycollection(b) IS NULL
from t1;

drop table t1;

--echo End of 4.1 tests
+17 −12
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ void Item_geometry_func::fix_length_and_dec()
  collation.set(&my_charset_bin);
  decimals=0;
  max_length=MAX_BLOB_WIDTH;
  maybe_null= 1;
}


@@ -109,6 +110,7 @@ String *Item_func_as_wkt::val_str(String *str)
void Item_func_as_wkt::fix_length_and_dec()
{
  max_length=MAX_BLOB_WIDTH;
  maybe_null= 1;
}


@@ -356,7 +358,8 @@ String *Item_func_spatial_collection::val_str(String *str)
  for (i= 0; i < arg_count; ++i)
  {
    String *res= args[i]->val_str(&arg_value);
    if (args[i]->null_value)
    uint32 len;
    if (args[i]->null_value || ((len= res->length()) < WKB_HEADER_SIZE))
      goto err;

    if (coll_type == Geometry::wkb_geometrycollection)
@@ -365,13 +368,12 @@ String *Item_func_spatial_collection::val_str(String *str)
	In the case of GeometryCollection we don't need any checkings
	for item types, so just copy them into target collection
      */
      if (str->append(res->ptr(), res->length(), (uint32) 512))
      if (str->append(res->ptr(), len, (uint32) 512))
        goto err;
    }
    else
    {
      enum Geometry::wkbType wkb_type;
      uint32 len=res->length();
      const char *data= res->ptr() + 1;

      /*
@@ -379,8 +381,6 @@ String *Item_func_spatial_collection::val_str(String *str)
	are of specific type, let's do this checking now
      */

      if (len < 5)
        goto err;
      wkb_type= (Geometry::wkbType) uint4korr(data);
      data+= 4;
      len-= 5;
@@ -503,8 +503,12 @@ longlong Item_func_isempty::val_int()
{
  DBUG_ASSERT(fixed == 1);
  String tmp;
  null_value=0;
  return args[0]->null_value ? 1 : 0;
  String *swkb= args[0]->val_str(&tmp);
  Geometry_buffer buffer;
  
  null_value= args[0]->null_value ||
              !(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
  return null_value ? 1 : 0;
}


@@ -512,10 +516,11 @@ longlong Item_func_issimple::val_int()
{
  DBUG_ASSERT(fixed == 1);
  String tmp;
  String *wkb=args[0]->val_str(&tmp);
  String *swkb= args[0]->val_str(&tmp);
  Geometry_buffer buffer;
  
  if ((null_value= (!wkb || args[0]->null_value)))
    return 0;
  null_value= args[0]->null_value ||
              !(Geometry::construct(&buffer, swkb->ptr(), swkb->length()));
  /* TODO: Ramil or Holyfoot, add real IsSimple calculation */
  return 0;
}
+32 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ class Item_geometry_func: public Item_str_func
  Item_geometry_func(List<Item> &list) :Item_str_func(list) {}
  void fix_length_and_dec();
  enum_field_types field_type() const  { return MYSQL_TYPE_GEOMETRY; }
  bool is_null() { (void) val_int(); return null_value; }
};

class Item_func_geometry_from_text: public Item_geometry_func
@@ -80,6 +81,7 @@ class Item_func_geometry_type: public Item_str_func
  void fix_length_and_dec() 
  {
     max_length=20; // "GeometryCollection" is the most long
     maybe_null= 1;
  };
};

@@ -221,6 +223,8 @@ class Item_func_spatial_rel: public Item_bool_func2
    }
    }
  void print(String *str) { Item_func::print(str); }
  void fix_length_and_dec() { maybe_null= 1; }
  bool is_null() { (void) val_int(); return null_value; }
};

class Item_func_isempty: public Item_bool_func
@@ -230,6 +234,7 @@ class Item_func_isempty: public Item_bool_func
  longlong val_int();
  optimize_type select_optimize() const { return OPTIMIZE_NONE; }
  const char *func_name() const { return "isempty"; }
  void fix_length_and_dec() { maybe_null= 1; }
};

class Item_func_issimple: public Item_bool_func
@@ -239,6 +244,7 @@ class Item_func_issimple: public Item_bool_func
  longlong val_int();
  optimize_type select_optimize() const { return OPTIMIZE_NONE; }
  const char *func_name() const { return "issimple"; }
  void fix_length_and_dec() { maybe_null= 1; }
};

class Item_func_isclosed: public Item_bool_func
@@ -248,6 +254,7 @@ class Item_func_isclosed: public Item_bool_func
  longlong val_int();
  optimize_type select_optimize() const { return OPTIMIZE_NONE; }
  const char *func_name() const { return "isclosed"; }
  void fix_length_and_dec() { maybe_null= 1; }
};

class Item_func_dimension: public Item_int_func
@@ -257,7 +264,7 @@ class Item_func_dimension: public Item_int_func
  Item_func_dimension(Item *a): Item_int_func(a) {}
  longlong val_int();
  const char *func_name() const { return "dimension"; }
  void fix_length_and_dec() { max_length=10; }
  void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};

class Item_func_x: public Item_real_func
@@ -267,6 +274,11 @@ class Item_func_x: public Item_real_func
  Item_func_x(Item *a): Item_real_func(a) {}
  double val();
  const char *func_name() const { return "x"; }
  void fix_length_and_dec() 
  { 
    Item_real_func::fix_length_and_dec();
    maybe_null= 1; 
  }
};


@@ -277,6 +289,11 @@ class Item_func_y: public Item_real_func
  Item_func_y(Item *a): Item_real_func(a) {}
  double val();
  const char *func_name() const { return "y"; }
  void fix_length_and_dec() 
  { 
    Item_real_func::fix_length_and_dec();
    maybe_null= 1; 
  }
};


@@ -287,7 +304,7 @@ class Item_func_numgeometries: public Item_int_func
  Item_func_numgeometries(Item *a): Item_int_func(a) {}
  longlong val_int();
  const char *func_name() const { return "numgeometries"; }
  void fix_length_and_dec() { max_length=10; }
  void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};


@@ -298,7 +315,7 @@ class Item_func_numinteriorring: public Item_int_func
  Item_func_numinteriorring(Item *a): Item_int_func(a) {}
  longlong val_int();
  const char *func_name() const { return "numinteriorrings"; }
  void fix_length_and_dec() { max_length=10; }
  void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};


@@ -309,7 +326,7 @@ class Item_func_numpoints: public Item_int_func
  Item_func_numpoints(Item *a): Item_int_func(a) {}
  longlong val_int();
  const char *func_name() const { return "numpoints"; }
  void fix_length_and_dec() { max_length=10; }
  void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};


@@ -320,6 +337,11 @@ class Item_func_area: public Item_real_func
  Item_func_area(Item *a): Item_real_func(a) {}
  double val();
  const char *func_name() const { return "area"; }
  void fix_length_and_dec() 
  { 
    Item_real_func::fix_length_and_dec();
    maybe_null= 1; 
  }
};


@@ -330,6 +352,11 @@ class Item_func_glength: public Item_real_func
  Item_func_glength(Item *a): Item_real_func(a) {}
  double val();
  const char *func_name() const { return "glength"; }
  void fix_length_and_dec() 
  { 
    Item_real_func::fix_length_and_dec();
    maybe_null= 1; 
  }
};


@@ -340,7 +367,7 @@ class Item_func_srid: public Item_int_func
  Item_func_srid(Item *a): Item_int_func(a) {}
  longlong val_int();
  const char *func_name() const { return "srid"; }
  void fix_length_and_dec() { max_length= 10; }
  void fix_length_and_dec() { max_length= 10; maybe_null= 1; }
};

#define GEOM_NEW(obj_constructor) new obj_constructor
+7 −6
Original line number Diff line number Diff line
@@ -210,23 +210,24 @@ static uint32 wkb_get_uint(const char *ptr, Geometry::wkbByteOrder bo)
}


int Geometry::create_from_wkb(Geometry_buffer *buffer,
Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
                                    const char *wkb, uint32 len, String *res)
{
  uint32 geom_type;
  Geometry *geom;

  if (len < WKB_HEADER_SIZE)
    return 1;
    return NULL;
  geom_type= wkb_get_uint(wkb+1, (wkbByteOrder)wkb[0]);
  if (!(geom= create_by_typeid(buffer, (int) geom_type)) ||
      res->reserve(WKB_HEADER_SIZE, 512))
    return 1;
    return NULL;

  res->q_append((char) wkb_ndr);
  res->q_append(geom_type);

  return geom->init_from_wkb(wkb + WKB_HEADER_SIZE, len - WKB_HEADER_SIZE,
                             (wkbByteOrder) wkb[0], res);
                             (wkbByteOrder) wkb[0], res) ? geom : NULL;
}


Loading