1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-31 22:22:30 +03:00

MDEV-19923 Add type handlers for geometry sub-types

This commit is contained in:
Alexander Barkov
2019-07-03 13:05:15 +04:00
parent c1519d62d0
commit b511202335
28 changed files with 1262 additions and 889 deletions

View File

@@ -101,15 +101,58 @@ const Type_collection *Type_handler::type_collection() const
#ifdef HAVE_SPATIAL
Type_handler_geometry type_handler_geometry;
Type_handler_geometry type_handler_geometry;
Type_handler_point type_handler_point;
Type_handler_linestring type_handler_linestring;
Type_handler_polygon type_handler_polygon;
Type_handler_multipoint type_handler_multipoint;
Type_handler_multilinestring type_handler_multilinestring;
Type_handler_multipolygon type_handler_multipolygon;
Type_handler_geometrycollection type_handler_geometrycollection;
const Type_handler_geometry *
Type_handler_geometry::type_handler_geom_by_type(uint type)
{
switch (type) {
case Type_handler_geometry::GEOM_POINT:
return &type_handler_point;
case Type_handler_geometry::GEOM_LINESTRING:
return &type_handler_linestring;
case Type_handler_geometry::GEOM_POLYGON:
return &type_handler_polygon;
case Type_handler_geometry::GEOM_MULTIPOINT:
return &type_handler_multipoint;
case Type_handler_geometry::GEOM_MULTILINESTRING:
return &type_handler_multilinestring;
case Type_handler_geometry::GEOM_MULTIPOLYGON:
return &type_handler_multipolygon;
case Type_handler_geometry::GEOM_GEOMETRYCOLLECTION:
return &type_handler_geometrycollection;
case Type_handler_geometry::GEOM_GEOMETRY:
break;
}
return &type_handler_geometry;
}
const Type_handler *
Type_handler_geometry::type_handler_frm_unpack(const uchar *buffer) const
{
// charset and geometry_type share the same byte in frm
return type_handler_geom_by_type((uint) buffer[14]);
}
class Type_collection_geometry: public Type_collection
{
const Type_handler *aggregate_common(const Type_handler *a,
const Type_handler *b) const
{
DBUG_ASSERT(a == &type_handler_geometry);
DBUG_ASSERT(b == &type_handler_geometry);
if (a == b)
return a;
DBUG_ASSERT(dynamic_cast<const Type_handler_geometry*>(a));
DBUG_ASSERT(dynamic_cast<const Type_handler_geometry*>(b));
return &type_handler_geometry;
}
public:
@@ -137,6 +180,56 @@ public:
{
return NULL;
}
bool init_aggregators(Type_handler_data *data, const Type_handler *geom) const
{
Type_aggregator *r= &data->m_type_aggregator_for_result;
Type_aggregator *c= &data->m_type_aggregator_for_comparison;
return
r->add(geom, &type_handler_null, geom) ||
r->add(geom, &type_handler_hex_hybrid, &type_handler_long_blob) ||
r->add(geom, &type_handler_tiny_blob, &type_handler_long_blob) ||
r->add(geom, &type_handler_blob, &type_handler_long_blob) ||
r->add(geom, &type_handler_medium_blob, &type_handler_long_blob) ||
r->add(geom, &type_handler_long_blob, &type_handler_long_blob) ||
r->add(geom, &type_handler_varchar, &type_handler_long_blob) ||
r->add(geom, &type_handler_string, &type_handler_long_blob) ||
c->add(geom, &type_handler_null, geom) ||
c->add(geom, &type_handler_long_blob, &type_handler_long_blob);
}
bool init(Type_handler_data *data) const
{
#ifndef DBUG_OFF
/*
The rules (geometry,geometry)->geometry and (pont,point)->geometry
are needed here to make sure
(in gis-debug.test) that they do not affect anything, and these pairs
returns an error in an expression like (POINT(0,0)+POINT(0,0)).
Both sides are from the same type collection here,
so aggregation goes only through Type_collection_xxx::aggregate_yyy()
and never reaches Type_aggregator::find_handler().
*/
Type_aggregator *nct= &data->m_type_aggregator_non_commutative_test;
if (nct->add(&type_handler_geometry,
&type_handler_geometry,
&type_handler_geometry) ||
nct->add(&type_handler_point,
&type_handler_point,
&type_handler_geometry) ||
nct->add(&type_handler_point,
&type_handler_varchar,
&type_handler_long_blob))
return true;
#endif
return
init_aggregators(data, &type_handler_geometry) ||
init_aggregators(data, &type_handler_geometrycollection) ||
init_aggregators(data, &type_handler_point) ||
init_aggregators(data, &type_handler_linestring) ||
init_aggregators(data, &type_handler_polygon) ||
init_aggregators(data, &type_handler_multipoint) ||
init_aggregators(data, &type_handler_multilinestring) ||
init_aggregators(data, &type_handler_multipolygon);
}
};
@@ -153,56 +246,7 @@ const Type_collection *Type_handler_geometry::type_collection() const
bool Type_handler_data::init()
{
#ifdef HAVE_SPATIAL
#ifndef DBUG_OFF
/*
The rule (geometry,geometry)->geometry is needed here to make sure
(in gis-debug.test) that is does not affect anything, and this pair
returns an error in an expression like (POINT(0,0)+POINT(0,0)).
Both sides are from the same type collection here,
so aggregation goes only through Type_collection_xxx::aggregate_yyy()
and never reaches Type_aggregator::find_handler().
*/
if (m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
&type_handler_geometry,
&type_handler_geometry) ||
m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
&type_handler_varchar,
&type_handler_long_blob))
return true;
#endif
return
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_null,
&type_handler_geometry) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_hex_hybrid,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_tiny_blob,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_blob,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_medium_blob,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_long_blob,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_varchar,
&type_handler_long_blob) ||
m_type_aggregator_for_result.add(&type_handler_geometry,
&type_handler_string,
&type_handler_long_blob) ||
m_type_aggregator_for_comparison.add(&type_handler_geometry,
&type_handler_null,
&type_handler_geometry) ||
m_type_aggregator_for_comparison.add(&type_handler_geometry,
&type_handler_long_blob,
&type_handler_long_blob);
return type_collection_geometry.init(this);
#endif
return false;
}
@@ -2358,8 +2402,51 @@ Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
#ifdef HAVE_SPATIAL
const Name Type_handler_geometry::m_name_geometry(STRING_WITH_LEN("geometry"));
bool Type_handler_geometry::check_type_geom_or_binary(const char *opname,
const Item *item)
{
const Type_handler *handler= item->type_handler();
if (handler->type_handler_for_comparison() == &type_handler_geometry ||
(handler->is_general_purpose_string_type() &&
item->collation.collation == &my_charset_bin))
return false;
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
handler->name().ptr(), opname);
return true;
}
bool Type_handler_geometry::check_types_geom_or_binary(const char *opname,
Item* const *args,
uint start, uint end)
{
for (uint i= start; i < end ; i++)
{
if (check_type_geom_or_binary(opname, args[i]))
return true;
}
return false;
}
const Name
Type_handler_geometry::
m_name_geometry(STRING_WITH_LEN("geometry")),
Type_handler_point::
m_name_point(STRING_WITH_LEN("point")),
Type_handler_linestring::
m_name_linestring(STRING_WITH_LEN("linestring")),
Type_handler_polygon::
m_name_polygon(STRING_WITH_LEN("polygon")),
Type_handler_multipoint::
m_name_multipoint(STRING_WITH_LEN("multipoint")),
Type_handler_multilinestring::
m_name_multilinestring(STRING_WITH_LEN("multilinestring")),
Type_handler_multipolygon::
m_name_multipolygon(STRING_WITH_LEN("multipolygon")),
Type_handler_geometrycollection::
m_name_geometrycollection(STRING_WITH_LEN("geometrycollection"));
const Type_handler *Type_handler_geometry::type_handler_for_comparison() const
{
@@ -2379,10 +2466,10 @@ Field *Type_handler_geometry::make_conversion_table_field(TABLE *table,
as this is only a temporary field.
The statistics was already incremented when "target" was created.
*/
const Field_geom *fg= static_cast<const Field_geom*>(target);
return new(table->in_use->mem_root)
Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, table->s, 4,
((const Field_geom*) target)->geom_type,
((const Field_geom*) target)->srid);
Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, 4, fg->type_handler_geom(), fg->srid);
}
#endif
@@ -2634,7 +2721,6 @@ void Type_handler_geometry::
Column_definition *def,
const Field *field) const
{
def->geom_type= ((Field_geom*) field)->geom_type;
def->srid= ((Field_geom*) field)->srid;
}
#endif
@@ -2973,6 +3059,193 @@ bool Type_handler_bit::
return false;
}
/*************************************************************************/
bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return false;
}
bool Type_handler::Key_part_spec_init_unique(Key_part_spec *part,
const Column_definition &def,
const handler *file,
bool *has_field_needed) const
{
part->length*= def.charset->mbmaxlen;
return false;
}
bool Type_handler::Key_part_spec_init_multiple(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return false;
}
bool Type_handler::Key_part_spec_init_foreign(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return false;
}
bool Type_handler::Key_part_spec_init_spatial(Key_part_spec *part,
const Column_definition &def)
const
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
return true;
}
bool Type_handler_blob_common::Key_part_spec_init_primary(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return part->check_primary_key_for_blob(file);
}
bool Type_handler_blob_common::Key_part_spec_init_unique(Key_part_spec *part,
const Column_definition &def,
const handler *file,
bool *hash_field_needed) const
{
if (!(part->length*= def.charset->mbmaxlen))
*hash_field_needed= true;
return part->check_key_for_blob(file);
}
bool Type_handler_blob_common::Key_part_spec_init_multiple(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return part->init_multiple_key_for_blob(file);
}
bool Type_handler_blob_common::Key_part_spec_init_foreign(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length*= def.charset->mbmaxlen;
return part->check_foreign_key_for_blob(file);
}
#ifdef HAVE_SPATIAL
bool Type_handler_geometry::Key_part_spec_init_primary(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
return part->check_primary_key_for_blob(file);
}
bool Type_handler_geometry::Key_part_spec_init_unique(Key_part_spec *part,
const Column_definition &def,
const handler *file,
bool *hash_field_needed) const
{
if (!part->length)
*hash_field_needed= true;
return part->check_key_for_blob(file);
}
bool Type_handler_geometry::Key_part_spec_init_multiple(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
return part->init_multiple_key_for_blob(file);
}
bool Type_handler_geometry::Key_part_spec_init_foreign(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
return part->check_foreign_key_for_blob(file);
}
bool Type_handler_geometry::Key_part_spec_init_spatial(Key_part_spec *part,
const Column_definition &def)
const
{
if (part->length)
{
my_error(ER_WRONG_SUB_KEY, MYF(0));
return true;
}
/*
4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
Lately we'll extend this code to support more dimensions
*/
part->length= 4 * sizeof(double);
return false;
}
bool Type_handler_point::Key_part_spec_init_primary(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
/*
QQ:
The below assignment (here and in all other Key_part_spec_init_xxx methods)
overrides the explicitly given key part length, so in this query:
CREATE OR REPLACE TABLE t1 (a POINT, KEY(a(10)));
the key becomes KEY(a(25)).
This might be a bug.
*/
part->length= octet_length();
return part->check_key_for_blob(file);
}
bool Type_handler_point::Key_part_spec_init_unique(Key_part_spec *part,
const Column_definition &def,
const handler *file,
bool *hash_field_needed) const
{
part->length= octet_length();
return part->check_key_for_blob(file);
}
bool Type_handler_point::Key_part_spec_init_multiple(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length= octet_length();
return part->check_key_for_blob(file);
}
bool Type_handler_point::Key_part_spec_init_foreign(Key_part_spec *part,
const Column_definition &def,
const handler *file) const
{
part->length= octet_length();
return part->check_key_for_blob(file);
}
#endif // HAVE_SPATIAL
/*************************************************************************/
uint32 Type_handler_time::calc_pack_length(uint32 length) const
@@ -3481,9 +3754,7 @@ Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name,
{
return new (table->in_use->mem_root)
Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, 4,
(Field::geometry_type) attr.uint_geometry_type(),
0);
Field::NONE, name, table->s, 4, this, 0);
}
#endif
@@ -4277,10 +4548,6 @@ bool Type_handler_geometry::
Item **items, uint nitems) const
{
DBUG_ASSERT(nitems > 0);
Type_geometry_attributes gattr(items[0]->type_handler(), 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;
@@ -6989,7 +7256,6 @@ bool Type_handler_geometry::
{
param->unsigned_flag= false;
param->setup_conversion_blob(thd);
param->set_geometry_type(attr->uint_geometry_type());
return param->set_str(val->m_string.ptr(), val->m_string.length(),
&my_charset_bin, &my_charset_bin);
}
@@ -7897,7 +8163,7 @@ Field *Type_handler_geometry::
return new (mem_root)
Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
attr->unireg_check, name, share,
attr->pack_flag_to_pack_length(), attr->geom_type, attr->srid);
attr->pack_flag_to_pack_length(), this, attr->srid);
}
#endif
@@ -8004,7 +8270,7 @@ void Type_handler_geometry::
{
def->frm_pack_basic(buff);
buff[11]= 0;
buff[14]= (uchar) def->geom_type;
buff[14]= (uchar) geometry_type();
}
#endif
@@ -8034,8 +8300,6 @@ bool Type_handler_geometry::
uint gis_opt_read, gis_length, gis_decimals;
Field_geom::storage_type st_type;
attr->frm_unpack_basic(buffer);
// charset and geometry_type share the same byte in frm
attr->geom_type= (Field::geometry_type) buffer[14];
gis_opt_read= gis_field_options_read(gis_options->str,
gis_options->length,
&st_type, &gis_length,