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:
404
sql/sql_type.cc
404
sql/sql_type.cc
@@ -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,
|
||||
|
Reference in New Issue
Block a user