MDEV-11042 Implement GeoJSON functions.
ST_AsGeoJSON and ST_GeomFromGeoJSON functions implemented.
This commit is contained in:
parent
1f3ad6a4ba
commit
0d107a85b3
66
mysql-test/r/gis-json.result
Normal file
66
mysql-test/r/gis-json.result
Normal file
@ -0,0 +1,66 @@
|
||||
select st_asgeojson(geomfromtext('POINT(1 1)'));
|
||||
st_asgeojson(geomfromtext('POINT(1 1)'))
|
||||
{"type": "POINT", "coordinates": [1, 1]}
|
||||
select st_asgeojson(geomfromtext('LINESTRING(10 10,20 10,20 20,10 20,10 10)'));
|
||||
st_asgeojson(geomfromtext('LINESTRING(10 10,20 10,20 20,10 20,10 10)'))
|
||||
{"type": "LINESTRING", "coordinates": [[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]}
|
||||
select st_asgeojson(geomfromtext('POLYGON((10 10,20 10,20 20,10 20,10 10))'));
|
||||
st_asgeojson(geomfromtext('POLYGON((10 10,20 10,20 20,10 20,10 10))'))
|
||||
{"type": "POLYGON", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}
|
||||
select st_asgeojson(geomfromtext('MULTIPOLYGON(((10 10,20 10,20 20,10 20,10 10)))'));
|
||||
st_asgeojson(geomfromtext('MULTIPOLYGON(((10 10,20 10,20 20,10 20,10 10)))'))
|
||||
{"type": "MULTIPOLYGON", "coordinates": [[[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]]}
|
||||
select st_asgeojson(geomfromtext('multilinestring((10 10,20 10,20 20,10 20,10 10))'));
|
||||
st_asgeojson(geomfromtext('multilinestring((10 10,20 10,20 20,10 20,10 10))'))
|
||||
{"type": "MULTILINESTRING", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}
|
||||
select st_asgeojson(geomfromtext('multipoint(10 10,20 10,20 20,10 20,10 10)'));
|
||||
st_asgeojson(geomfromtext('multipoint(10 10,20 10,20 20,10 20,10 10)'))
|
||||
{"type": "MULTIPOINT", "coordinates": [[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]}
|
||||
select st_asgeojson(st_geomfromtext('GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))'));
|
||||
st_asgeojson(st_geomfromtext('GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))'))
|
||||
{"type": "GEOMETRYCOLLECTION", "geometries": [{"type": "POINT", "coordinates": [100, 0]}, {"type": "LINESTRING", "coordinates": [[101, 0], [102, 1]]}]}
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point","coordinates":[1,2]}'));
|
||||
st_astext(st_geomfromgeojson('{"type":"point","coordinates":[1,2]}'))
|
||||
POINT(1 2)
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"LineString","coordinates":[[1,2],[4,5],[7,8]]}'));
|
||||
st_astext(st_geomfromgeojson('{"type":"LineString","coordinates":[[1,2],[4,5],[7,8]]}'))
|
||||
LINESTRING(1 2,4 5,7 8)
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "polygon", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'));
|
||||
st_astext(st_geomfromgeojson('{"type": "polygon", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'))
|
||||
POLYGON((10 10,20 10,20 20,10 20,10 10))
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"multipoint","coordinates":[[1,2],[4,5],[7,8]]}'));
|
||||
st_astext(st_geomfromgeojson('{"type":"multipoint","coordinates":[[1,2],[4,5],[7,8]]}'))
|
||||
MULTIPOINT(1 2,4 5,7 8)
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "multilinestring", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'));
|
||||
st_astext(st_geomfromgeojson('{"type": "multilinestring", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'))
|
||||
MULTILINESTRING((10 10,20 10,20 20,10 20,10 10))
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "multipolygon", "coordinates": [[[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]]}'));
|
||||
st_astext(st_geomfromgeojson('{"type": "multipolygon", "coordinates": [[[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]]}'))
|
||||
MULTIPOLYGON(((10 10,20 10,20 20,10 20,10 10)))
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "GeometryCollection", "geometries": [{"type": "Point","coordinates": [100.0, 0.0]}, {"type": "LineString","coordinates": [[101.0, 0.0],[102.0, 1.0]]}]}'));
|
||||
st_astext(st_geomfromgeojson('{"type": "GeometryCollection", "geometries": [{"type": "Point","coordinates": [100.0, 0.0]}, {"type": "LineString","coordinates": [[101.0, 0.0],[102.0, 1.0]]}]}'))
|
||||
GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point"}'));
|
||||
st_astext(st_geomfromgeojson('{"type":"point"}'))
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 4048 Incorrect GeoJSON format specified for st_geomfromgeojson function.
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point"'));
|
||||
st_astext(st_geomfromgeojson('{"type":"point"'))
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 4037 Unexpected end of JSON text in argument 1 to function 'st_geomfromgeojson'
|
||||
SELECT st_astext(st_geomfromgeojson('{"type""point"}'));
|
||||
st_astext(st_geomfromgeojson('{"type""point"}'))
|
||||
NULL
|
||||
Warnings:
|
||||
Warning 4038 Syntax error in JSON text in argument 1 to function 'st_geomfromgeojson' at position 7
|
||||
SELECT st_astext(st_geomfromgeojson('{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] } }'));
|
||||
st_astext(st_geomfromgeojson('{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] } }'))
|
||||
POINT(102 0.5)
|
||||
SELECT st_astext(st_geomfromgeojson('{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] }, "properties": { "prop0": "value0" } }]}'));
|
||||
st_astext(st_geomfromgeojson('{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] }, "properties": { "prop0": "value0" } }]}'))
|
||||
GEOMETRYCOLLECTION(POINT(102 0.5))
|
||||
#
|
||||
# End of 10.2 tests
|
||||
#
|
28
mysql-test/t/gis-json.test
Normal file
28
mysql-test/t/gis-json.test
Normal file
@ -0,0 +1,28 @@
|
||||
-- source include/have_geometry.inc
|
||||
|
||||
select st_asgeojson(geomfromtext('POINT(1 1)'));
|
||||
select st_asgeojson(geomfromtext('LINESTRING(10 10,20 10,20 20,10 20,10 10)'));
|
||||
select st_asgeojson(geomfromtext('POLYGON((10 10,20 10,20 20,10 20,10 10))'));
|
||||
select st_asgeojson(geomfromtext('MULTIPOLYGON(((10 10,20 10,20 20,10 20,10 10)))'));
|
||||
select st_asgeojson(geomfromtext('multilinestring((10 10,20 10,20 20,10 20,10 10))'));
|
||||
select st_asgeojson(geomfromtext('multipoint(10 10,20 10,20 20,10 20,10 10)'));
|
||||
select st_asgeojson(st_geomfromtext('GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))'));
|
||||
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point","coordinates":[1,2]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"LineString","coordinates":[[1,2],[4,5],[7,8]]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "polygon", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"multipoint","coordinates":[[1,2],[4,5],[7,8]]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "multilinestring", "coordinates": [[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "multipolygon", "coordinates": [[[[10, 10], [20, 10], [20, 20], [10, 20], [10, 10]]]]}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type": "GeometryCollection", "geometries": [{"type": "Point","coordinates": [100.0, 0.0]}, {"type": "LineString","coordinates": [[101.0, 0.0],[102.0, 1.0]]}]}'));
|
||||
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point"}'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type":"point"'));
|
||||
SELECT st_astext(st_geomfromgeojson('{"type""point"}'));
|
||||
|
||||
SELECT st_astext(st_geomfromgeojson('{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] } }'));
|
||||
SELECT st_astext(st_geomfromgeojson('{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [102.0, 0.5] }, "properties": { "prop0": "value0" } }]}'));
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.2 tests
|
||||
--echo #
|
@ -1261,6 +1261,34 @@ protected:
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
class Create_func_geometry_from_json : public Create_native_func
|
||||
{
|
||||
public:
|
||||
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
|
||||
|
||||
static Create_func_geometry_from_json s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_geometry_from_json() {}
|
||||
virtual ~Create_func_geometry_from_json() {}
|
||||
};
|
||||
|
||||
|
||||
class Create_func_as_geojson : public Create_native_func
|
||||
{
|
||||
public:
|
||||
virtual Item *create_native(THD *thd, LEX_STRING name, List<Item> *item_list);
|
||||
|
||||
static Create_func_as_geojson s_singleton;
|
||||
|
||||
protected:
|
||||
Create_func_as_geojson() {}
|
||||
virtual ~Create_func_as_geojson() {}
|
||||
};
|
||||
#endif /*HAVE_SPATIAL*/
|
||||
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
class Create_func_geometry_type : public Create_func_arg1
|
||||
{
|
||||
@ -4532,6 +4560,101 @@ Create_func_geometry_from_wkb::create_native(THD *thd, LEX_STRING name,
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_geometry_from_json::create_native(THD *thd, LEX_STRING name,
|
||||
List<Item> *item_list)
|
||||
{
|
||||
Item *func= NULL;
|
||||
int arg_count= 0;
|
||||
|
||||
if (item_list != NULL)
|
||||
arg_count= item_list->elements;
|
||||
|
||||
switch (arg_count) {
|
||||
case 1:
|
||||
{
|
||||
Item *json= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
|
||||
thd->lex->uncacheable(UNCACHEABLE_RAND);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Item *json= item_list->pop();
|
||||
Item *options= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Item *json= item_list->pop();
|
||||
Item *options= item_list->pop();
|
||||
Item *srid= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
|
||||
srid);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
Create_func_as_geojson Create_func_as_geojson::s_singleton;
|
||||
|
||||
Item*
|
||||
Create_func_as_geojson::create_native(THD *thd, LEX_STRING name,
|
||||
List<Item> *item_list)
|
||||
{
|
||||
Item *func= NULL;
|
||||
int arg_count= 0;
|
||||
|
||||
if (item_list != NULL)
|
||||
arg_count= item_list->elements;
|
||||
|
||||
switch (arg_count) {
|
||||
case 1:
|
||||
{
|
||||
Item *geom= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
|
||||
thd->lex->uncacheable(UNCACHEABLE_RAND);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
Item *geom= item_list->pop();
|
||||
Item *max_dec= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
Item *geom= item_list->pop();
|
||||
Item *max_dec= item_list->pop();
|
||||
Item *options= item_list->pop();
|
||||
func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name.str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
#endif /*HAVE_SPATIAL*/
|
||||
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
Create_func_geometry_type Create_func_geometry_type::s_singleton;
|
||||
|
||||
@ -6723,6 +6846,7 @@ static Native_func_registry func_array[] =
|
||||
{ { C_STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)},
|
||||
{ { C_STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
|
||||
{ { C_STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
|
||||
{ { C_STRING_WITH_LEN("ST_ASGEOJSON") }, GEOM_BUILDER(Create_func_as_geojson)},
|
||||
{ { C_STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
|
||||
{ { C_STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
|
||||
{ { C_STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
|
||||
@ -6748,6 +6872,7 @@ static Native_func_registry func_array[] =
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMFROMGEOJSON") }, GEOM_BUILDER(Create_func_geometry_from_json)},
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
|
||||
{ { C_STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
|
||||
#ifndef DBUG_OFF
|
||||
|
@ -121,6 +121,65 @@ String *Item_func_geometry_from_wkb::val_str(String *str)
|
||||
}
|
||||
|
||||
|
||||
void report_json_error_ex(String *js, json_engine_t *je,
|
||||
const char *fname, int n_param,
|
||||
Sql_condition::enum_warning_level lv);
|
||||
|
||||
String *Item_func_geometry_from_json::val_str(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
Geometry_buffer buffer;
|
||||
String *js= args[0]->val_str_ascii(&tmp_js);
|
||||
uint32 srid= 0;
|
||||
json_engine_t je;
|
||||
|
||||
if ((null_value= args[0]->null_value))
|
||||
return 0;
|
||||
|
||||
if ((arg_count == 2) && !args[1]->null_value)
|
||||
srid= (uint32)args[1]->val_int();
|
||||
|
||||
str->set_charset(&my_charset_bin);
|
||||
if (str->reserve(SRID_SIZE, 512))
|
||||
return 0;
|
||||
str->length(0);
|
||||
str->q_append(srid);
|
||||
|
||||
json_scan_start(&je, js->charset(), (const uchar *) js->ptr(),
|
||||
(const uchar *) js->end());
|
||||
|
||||
if ((null_value= !Geometry::create_from_json(&buffer, &je, str)))
|
||||
{
|
||||
int code= 0;
|
||||
|
||||
switch (je.s.error)
|
||||
{
|
||||
case Geometry::GEOJ_INCORRECT_GEOJSON:
|
||||
code= ER_GEOJSON_INCORRECT;
|
||||
break;
|
||||
case Geometry::GEOJ_TOO_FEW_POINTS:
|
||||
code= ER_GEOJSON_TOO_FEW_POINTS;
|
||||
break;
|
||||
case Geometry::GEOJ_POLYGON_NOT_CLOSED:
|
||||
code= ER_GEOJSON_NOT_CLOSED;
|
||||
break;
|
||||
default:
|
||||
report_json_error_ex(js, &je, func_name(), 0, Sql_condition::WARN_LEVEL_WARN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (code)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, code,
|
||||
ER_THD(thd, code));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_as_wkt::val_str_ascii(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
@ -170,6 +229,37 @@ String *Item_func_as_wkb::val_str(String *str)
|
||||
}
|
||||
|
||||
|
||||
void Item_func_as_geojson::fix_length_and_dec()
|
||||
{
|
||||
collation.set(default_charset(), DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
|
||||
max_length=MAX_BLOB_WIDTH;
|
||||
maybe_null= 1;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_as_geojson::val_str_ascii(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
String arg_val;
|
||||
String *swkb= args[0]->val_str(&arg_val);
|
||||
Geometry_buffer buffer;
|
||||
Geometry *geom= NULL;
|
||||
const char *dummy;
|
||||
|
||||
if ((null_value=
|
||||
(args[0]->null_value ||
|
||||
!(geom= Geometry::construct(&buffer, swkb->ptr(), swkb->length())))))
|
||||
return 0;
|
||||
|
||||
str->length(0);
|
||||
str->set_charset(&my_charset_latin1);
|
||||
if ((null_value= geom->as_json(str, FLOATING_POINT_DECIMALS, &dummy)))
|
||||
return 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
String *Item_func_geometry_type::val_str_ascii(String *str)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
|
@ -67,6 +67,23 @@ public:
|
||||
{ return get_item_copy<Item_func_geometry_from_wkb>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_geometry_from_json: public Item_geometry_func
|
||||
{
|
||||
String tmp_js;
|
||||
public:
|
||||
Item_func_geometry_from_json(THD *thd, Item *js): Item_geometry_func(thd, js) {}
|
||||
Item_func_geometry_from_json(THD *thd, Item *js, Item *opt):
|
||||
Item_geometry_func(thd, js, opt) {}
|
||||
Item_func_geometry_from_json(THD *thd, Item *js, Item *opt, Item *srid):
|
||||
Item_geometry_func(thd, js, opt, srid) {}
|
||||
const char *func_name() const { return "st_geomfromgeojson"; }
|
||||
String *val_str(String *);
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_geometry_from_json>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_as_wkt: public Item_str_ascii_func
|
||||
{
|
||||
public:
|
||||
@ -89,6 +106,23 @@ public:
|
||||
{ return get_item_copy<Item_func_as_wkb>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_as_geojson: public Item_str_ascii_func
|
||||
{
|
||||
public:
|
||||
Item_func_as_geojson(THD *thd, Item *js): Item_str_ascii_func(thd, js) {}
|
||||
Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits):
|
||||
Item_str_ascii_func(thd, js, max_dec_digits) {}
|
||||
Item_func_as_geojson(THD *thd, Item *js, Item *max_dec_digits, Item *opt):
|
||||
Item_str_ascii_func(thd, js, max_dec_digits, opt) {}
|
||||
const char *func_name() const { return "st_asgeojson"; }
|
||||
void fix_length_and_dec();
|
||||
String *val_str_ascii(String *);
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_as_geojson>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_geometry_type: public Item_str_ascii_func
|
||||
{
|
||||
public:
|
||||
|
@ -117,7 +117,7 @@ static int st_append_escaped(String *s, const String *a)
|
||||
report_json_error_ex(js, je, func_name(), n_param, \
|
||||
Sql_condition::WARN_LEVEL_WARN)
|
||||
|
||||
static void report_json_error_ex(String *js, json_engine_t *je,
|
||||
void report_json_error_ex(String *js, json_engine_t *je,
|
||||
const char *fname, int n_param,
|
||||
Sql_condition::enum_warning_level lv)
|
||||
{
|
||||
|
@ -7440,3 +7440,9 @@ ER_JSON_ONE_OR_ALL
|
||||
eng "Argument 2 to function '%s' must be "one" or "all"."
|
||||
ER_UNSUPPORT_COMPRESSED_TEMPORARY_TABLE
|
||||
eng "CREATE TEMPORARY TABLE is not allowed with ROW_FORMAT=COMPRESSED or KEY_BLOCK_SIZE."
|
||||
ER_GEOJSON_INCORRECT
|
||||
eng "Incorrect GeoJSON format specified for st_geomfromgeojson function."
|
||||
ER_GEOJSON_TOO_FEW_POINTS
|
||||
eng "Incorrect GeoJSON format - too few points for linestring specified."
|
||||
ER_GEOJSON_NOT_CLOSED
|
||||
eng "Incorrect GeoJSON format - polygon not closed."
|
||||
|
760
sql/spatial.cc
760
sql/spatial.cc
@ -230,6 +230,50 @@ int Geometry::as_wkt(String *wkt, const char **end)
|
||||
}
|
||||
|
||||
|
||||
static const uchar type_keyname[]= "type";
|
||||
static const int type_keyname_len= 4;
|
||||
static const uchar coord_keyname[]= "coordinates";
|
||||
static const int coord_keyname_len= 11;
|
||||
static const uchar geometries_keyname[]= "geometries";
|
||||
static const int geometries_keyname_len= 10;
|
||||
static const uchar features_keyname[]= "features";
|
||||
static const int features_keyname_len= 8;
|
||||
static const uchar geometry_keyname[]= "geometry";
|
||||
static const int geometry_keyname_len= 8;
|
||||
|
||||
static const int max_keyname_len= 11; /*'coordinates' keyname is the longest.*/
|
||||
|
||||
static const uchar feature_type[]= "feature";
|
||||
static const int feature_type_len= 7;
|
||||
static const uchar feature_coll_type[]= "featurecollection";
|
||||
static const int feature_coll_type_len= 17;
|
||||
|
||||
|
||||
int Geometry::as_json(String *wkt, uint max_dec_digits, const char **end)
|
||||
{
|
||||
uint32 len= (uint) get_class_info()->m_name.length;
|
||||
if (wkt->reserve(4 + type_keyname_len + 2 + len + 2 + 2 +
|
||||
coord_keyname_len + 4, 512))
|
||||
return 1;
|
||||
wkt->qs_append("{\"", 2);
|
||||
wkt->qs_append((const char *) type_keyname, type_keyname_len);
|
||||
wkt->qs_append("\": \"", 4);
|
||||
wkt->qs_append(get_class_info()->m_name.str, len);
|
||||
wkt->qs_append("\", \"", 4);
|
||||
if (get_class_info() == &geometrycollection_class)
|
||||
wkt->qs_append((const char *) geometries_keyname, geometries_keyname_len);
|
||||
else
|
||||
wkt->qs_append((const char *) coord_keyname, coord_keyname_len);
|
||||
|
||||
wkt->qs_append("\": ", 3);
|
||||
if (get_data_as_json(wkt, max_dec_digits, end) ||
|
||||
wkt->reserve(1))
|
||||
return 1;
|
||||
wkt->qs_append('}');
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo)
|
||||
{
|
||||
double res;
|
||||
@ -291,6 +335,196 @@ Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer,
|
||||
}
|
||||
|
||||
|
||||
Geometry *Geometry::create_from_json(Geometry_buffer *buffer,
|
||||
json_engine_t *je, String *res)
|
||||
{
|
||||
Class_info *ci= NULL;
|
||||
const uchar *coord_start= NULL, *geom_start= NULL,
|
||||
*features_start= NULL, *geometry_start= NULL;
|
||||
Geometry *result;
|
||||
uchar key_buf[max_keyname_len];
|
||||
uint key_len;
|
||||
int fcoll_type_found= 0, feature_type_found= 0;
|
||||
|
||||
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
|
||||
if (je->value_type != JSON_VALUE_OBJECT)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
goto err_return;
|
||||
}
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_OBJ_END)
|
||||
{
|
||||
DBUG_ASSERT(je->state == JST_KEY);
|
||||
|
||||
key_len=0;
|
||||
while (json_read_keyname_chr(je) == 0)
|
||||
{
|
||||
if (je->s.c_next > 127 || key_len >= max_keyname_len)
|
||||
{
|
||||
/* Symbol out of range, or keyname too long. No need to compare.. */
|
||||
key_len=0;
|
||||
break;
|
||||
}
|
||||
key_buf[key_len++]= je->s.c_next | 0x20; /* make it lowercase. */
|
||||
}
|
||||
|
||||
if (je->s.error)
|
||||
goto err_return;
|
||||
|
||||
if (key_len == type_keyname_len &&
|
||||
memcmp(key_buf, type_keyname, type_keyname_len) == 0)
|
||||
{
|
||||
/*
|
||||
Found the "type" key. Let's check it's a string and remember
|
||||
the feature's type.
|
||||
*/
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
|
||||
if (je->value_type == JSON_VALUE_STRING)
|
||||
{
|
||||
if ((ci= find_class((const char *) je->value, je->value_len)))
|
||||
{
|
||||
if ((coord_start=
|
||||
(ci == &geometrycollection_class) ? geom_start : coord_start))
|
||||
goto create_geom;
|
||||
}
|
||||
else if (je->value_len == feature_coll_type_len &&
|
||||
my_strnncoll(&my_charset_latin1, je->value, je->value_len,
|
||||
feature_coll_type, feature_coll_type_len) == 0)
|
||||
{
|
||||
/*
|
||||
'FeatureCollection' type found. Handle the 'Featurecollection'/'features'
|
||||
GeoJSON construction.
|
||||
*/
|
||||
if (features_start)
|
||||
goto handle_feature_collection;
|
||||
fcoll_type_found= 1;
|
||||
}
|
||||
else if (je->value_len == feature_type_len &&
|
||||
my_strnncoll(&my_charset_latin1, je->value, je->value_len,
|
||||
feature_type, feature_type_len) == 0)
|
||||
{
|
||||
if (geometry_start)
|
||||
goto handle_geometry_key;
|
||||
feature_type_found= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key_len == coord_keyname_len &&
|
||||
memcmp(key_buf, coord_keyname, coord_keyname_len) == 0)
|
||||
{
|
||||
/*
|
||||
Found the "coordinates" key. Let's check it's an array
|
||||
and remember where it starts.
|
||||
*/
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
|
||||
if (je->value_type == JSON_VALUE_ARRAY)
|
||||
{
|
||||
coord_start= je->value_begin;
|
||||
if (ci && ci != &geometrycollection_class)
|
||||
goto create_geom;
|
||||
}
|
||||
}
|
||||
else if (key_len == geometries_keyname_len &&
|
||||
memcmp(key_buf, geometries_keyname, geometries_keyname_len) == 0)
|
||||
{
|
||||
/*
|
||||
Found the "geometries" key. Let's check it's an array
|
||||
and remember where it starts.
|
||||
*/
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
|
||||
if (je->value_type == JSON_VALUE_ARRAY)
|
||||
{
|
||||
geom_start= je->value_begin;
|
||||
if (ci == &geometrycollection_class)
|
||||
{
|
||||
coord_start= geom_start;
|
||||
goto create_geom;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key_len == features_keyname_len &&
|
||||
memcmp(key_buf, features_keyname, features_keyname_len) == 0)
|
||||
{
|
||||
/*
|
||||
'features' key found. Handle the 'Featurecollection'/'features'
|
||||
GeoJSON construction.
|
||||
*/
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
if (je->value_type == JSON_VALUE_ARRAY)
|
||||
{
|
||||
features_start= je->value_begin;
|
||||
if (fcoll_type_found)
|
||||
goto handle_feature_collection;
|
||||
}
|
||||
}
|
||||
else if (key_len == geometry_keyname_len &&
|
||||
memcmp(key_buf, geometry_keyname, geometry_keyname_len) == 0)
|
||||
{
|
||||
if (json_read_value(je))
|
||||
goto err_return;
|
||||
if (je->value_type == JSON_VALUE_OBJECT)
|
||||
{
|
||||
geometry_start= je->value_begin;
|
||||
if (feature_type_found)
|
||||
goto handle_geometry_key;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (json_skip_key(je))
|
||||
goto err_return;
|
||||
}
|
||||
}
|
||||
|
||||
if (je->s.error == 0)
|
||||
{
|
||||
/*
|
||||
We didn't find all the required keys. That are "type" and "coordinates"
|
||||
or "geometries" for GeometryCollection.
|
||||
*/
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
}
|
||||
goto err_return;
|
||||
|
||||
handle_feature_collection:
|
||||
ci= &geometrycollection_class;
|
||||
coord_start= features_start;
|
||||
|
||||
create_geom:
|
||||
|
||||
json_scan_start(je, je->s.cs, coord_start, je->s.str_end);
|
||||
|
||||
if (res->reserve(1 + 4, 512))
|
||||
goto err_return;
|
||||
|
||||
result= (*ci->m_create_func)(buffer->data);
|
||||
res->q_append((char) wkb_ndr);
|
||||
res->q_append((uint32) result->get_class_info()->m_type_id);
|
||||
if (result->init_from_json(je, res))
|
||||
goto err_return;
|
||||
|
||||
return result;
|
||||
|
||||
handle_geometry_key:
|
||||
json_scan_start(je, je->s.cs, geometry_start, je->s.str_end);
|
||||
return create_from_json(buffer, je, res);
|
||||
|
||||
err_return:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Geometry *Geometry::create_from_opresult(Geometry_buffer *g_buf,
|
||||
String *res, Gcalc_result_receiver &rr)
|
||||
{
|
||||
@ -429,6 +663,47 @@ const char *Geometry::append_points(String *txt, uint32 n_points,
|
||||
}
|
||||
|
||||
|
||||
static void append_json_point(String *txt, uint max_dec, const char *data)
|
||||
{
|
||||
double x,y;
|
||||
get_point(&x, &y, data);
|
||||
txt->qs_append('[');
|
||||
txt->qs_append(x);
|
||||
txt->qs_append(", ", 2);
|
||||
txt->qs_append(y);
|
||||
txt->qs_append(']');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Append N points from packed format to json
|
||||
|
||||
SYNOPSIS
|
||||
append_json_points()
|
||||
txt Append points here
|
||||
n_points Number of points
|
||||
data Packed data
|
||||
offset Offset between points
|
||||
|
||||
RETURN
|
||||
# end of data
|
||||
*/
|
||||
|
||||
static const char *append_json_points(String *txt, uint max_dec,
|
||||
uint32 n_points, const char *data, uint32 offset)
|
||||
{
|
||||
txt->qs_append('[');
|
||||
while (n_points--)
|
||||
{
|
||||
data+= offset;
|
||||
append_json_point(txt, max_dec, data);
|
||||
data+= POINT_DATA_SIZE;
|
||||
txt->qs_append(", ", 2);
|
||||
}
|
||||
txt->length(txt->length() - 2);// Remove ending ', '
|
||||
txt->qs_append(']');
|
||||
return data;
|
||||
}
|
||||
/*
|
||||
Get most bounding rectangle (mbr) for X points
|
||||
|
||||
@ -502,6 +777,58 @@ uint Gis_point::init_from_wkb(const char *wkb, uint len,
|
||||
}
|
||||
|
||||
|
||||
static int read_point_from_json(json_engine_t *je, double *x, double *y)
|
||||
{
|
||||
int n_coord= 0, err;
|
||||
double tmp, *d;
|
||||
char *endptr;
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
if (json_read_value(je))
|
||||
return 1;
|
||||
|
||||
if (je->value_type != JSON_VALUE_NUMBER)
|
||||
goto bad_coordinates;
|
||||
|
||||
d= (n_coord == 0) ? x : ((n_coord == 1) ? y : &tmp);
|
||||
*d= my_strntod(je->s.cs, (char *) je->value,
|
||||
je->value_len, &endptr, &err);
|
||||
if (err)
|
||||
goto bad_coordinates;
|
||||
n_coord++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bad_coordinates:
|
||||
je->s.error= Geometry::GEOJ_INCORRECT_GEOJSON;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_point::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
double x, y;
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (read_point_from_json(je, &x, &y) ||
|
||||
wkb->reserve(POINT_DATA_SIZE))
|
||||
return TRUE;
|
||||
|
||||
wkb->q_append(x);
|
||||
wkb->q_append(y);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
|
||||
{
|
||||
double x, y;
|
||||
@ -517,6 +844,17 @@ bool Gis_point::get_data_as_wkt(String *txt, const char **end) const
|
||||
}
|
||||
|
||||
|
||||
bool Gis_point::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 4))
|
||||
return 1;
|
||||
append_json_point(txt, max_dec_digits, m_data);
|
||||
*end= m_data+ POINT_DATA_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_point::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
double x, y;
|
||||
@ -630,6 +968,43 @@ uint Gis_line_string::init_from_wkb(const char *wkb, uint len,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_line_string::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_points= 0;
|
||||
uint32 np_pos= wkb->length();
|
||||
Gis_point p;
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_points
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
if (p.init_from_json(je, wkb))
|
||||
return TRUE;
|
||||
n_points++;
|
||||
}
|
||||
if (n_points < 1)
|
||||
{
|
||||
je->s.error= GEOJ_TOO_FEW_POINTS;
|
||||
return TRUE;
|
||||
}
|
||||
wkb->write_at_position(np_pos, n_points);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
|
||||
{
|
||||
uint32 n_points;
|
||||
@ -661,6 +1036,28 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const
|
||||
}
|
||||
|
||||
|
||||
bool Gis_line_string::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_points;
|
||||
const char *data= m_data;
|
||||
|
||||
if (no_data(data, 4))
|
||||
return 1;
|
||||
n_points= uint4korr(data);
|
||||
data += 4;
|
||||
|
||||
if (n_points < 1 ||
|
||||
not_enough_points(data, n_points) ||
|
||||
txt->reserve((MAX_DIGITS_IN_DOUBLE*2 + 6) * n_points + 2))
|
||||
return 1;
|
||||
|
||||
*end= append_json_points(txt, max_dec_digits, n_points, data, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0;
|
||||
@ -854,7 +1251,7 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb)
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return 1;
|
||||
wkb->length(wkb->length()+4); // Reserve space for points
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_rings
|
||||
for (;;)
|
||||
{
|
||||
Gis_line_string ls;
|
||||
@ -964,6 +1361,46 @@ uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_polygon::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_linear_rings= 0;
|
||||
uint32 lr_pos= wkb->length();
|
||||
int closed;
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_rings
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
Gis_line_string ls;
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
uint32 ls_pos=wkb->length();
|
||||
if (ls.init_from_json(je, wkb))
|
||||
return TRUE;
|
||||
ls.set_data_ptr(wkb->ptr() + ls_pos, wkb->length() - ls_pos);
|
||||
if (ls.is_closed(&closed) || !closed)
|
||||
{
|
||||
je->s.error= GEOJ_POLYGON_NOT_CLOSED;
|
||||
return TRUE;
|
||||
}
|
||||
n_linear_rings++;
|
||||
}
|
||||
wkb->write_at_position(lr_pos, n_linear_rings);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
|
||||
{
|
||||
uint32 n_linear_rings;
|
||||
@ -996,6 +1433,39 @@ bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const
|
||||
}
|
||||
|
||||
|
||||
bool Gis_polygon::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_linear_rings;
|
||||
const char *data= m_data;
|
||||
|
||||
if (no_data(data, 4) || txt->reserve(1, 512))
|
||||
return 1;
|
||||
|
||||
n_linear_rings= uint4korr(data);
|
||||
data+= 4;
|
||||
|
||||
txt->qs_append('[');
|
||||
while (n_linear_rings--)
|
||||
{
|
||||
uint32 n_points;
|
||||
if (no_data(data, 4))
|
||||
return 1;
|
||||
n_points= uint4korr(data);
|
||||
data+= 4;
|
||||
if (not_enough_points(data, n_points) ||
|
||||
txt->reserve(4 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
|
||||
return 1;
|
||||
data= append_json_points(txt, max_dec_digits, n_points, data, 0);
|
||||
txt->qs_append(", ", 2);
|
||||
}
|
||||
txt->length(txt->length() - 2);// Remove ending ', '
|
||||
txt->qs_append(']');
|
||||
*end= data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
uint32 n_linear_rings;
|
||||
@ -1382,6 +1852,44 @@ uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_point::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_points= 0;
|
||||
uint32 np_pos= wkb->length();
|
||||
Gis_point p;
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_points
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
if (wkb->reserve(1 + 4, 512))
|
||||
return TRUE;
|
||||
wkb->q_append((char) wkb_ndr);
|
||||
wkb->q_append((uint32) wkb_point);
|
||||
|
||||
if (p.init_from_json(je, wkb))
|
||||
return TRUE;
|
||||
n_points++;
|
||||
}
|
||||
|
||||
wkb->write_at_position(np_pos, n_points);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
|
||||
{
|
||||
uint32 n_points;
|
||||
@ -1399,6 +1907,24 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_point::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_points;
|
||||
if (no_data(m_data, 4))
|
||||
return 1;
|
||||
|
||||
n_points= uint4korr(m_data);
|
||||
if (n_points > max_n_points ||
|
||||
not_enough_points(m_data+4, n_points, WKB_HEADER_SIZE) ||
|
||||
txt->reserve((MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points + 2))
|
||||
return 1;
|
||||
*end= append_json_points(txt, max_dec_digits, n_points, m_data+4,
|
||||
WKB_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0;
|
||||
@ -1594,6 +2120,44 @@ uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_line_string::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_line_strings= 0;
|
||||
uint32 ls_pos= wkb->length();
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_rings
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
Gis_line_string ls;
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
if (wkb->reserve(1 + 4, 512))
|
||||
return TRUE;
|
||||
wkb->q_append((char) wkb_ndr);
|
||||
wkb->q_append((uint32) wkb_linestring);
|
||||
|
||||
if (ls.init_from_json(je, wkb))
|
||||
return TRUE;
|
||||
|
||||
n_line_strings++;
|
||||
}
|
||||
wkb->write_at_position(ls_pos, n_line_strings);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_line_string::get_data_as_wkt(String *txt,
|
||||
const char **end) const
|
||||
{
|
||||
@ -1626,6 +2190,38 @@ bool Gis_multi_line_string::get_data_as_wkt(String *txt,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_line_string::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_line_strings;
|
||||
const char *data= m_data;
|
||||
|
||||
if (no_data(data, 4) || txt->reserve(1, 512))
|
||||
return 1;
|
||||
n_line_strings= uint4korr(data);
|
||||
data+= 4;
|
||||
|
||||
txt->qs_append('[');
|
||||
while (n_line_strings--)
|
||||
{
|
||||
uint32 n_points;
|
||||
if (no_data(data, (WKB_HEADER_SIZE + 4)))
|
||||
return 1;
|
||||
n_points= uint4korr(data + WKB_HEADER_SIZE);
|
||||
data+= WKB_HEADER_SIZE + 4;
|
||||
if (not_enough_points(data, n_points) ||
|
||||
txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points))
|
||||
return 1;
|
||||
data= append_json_points(txt, max_dec_digits, n_points, data, 0);
|
||||
txt->qs_append(", ", 2);
|
||||
}
|
||||
txt->length(txt->length() - 2);
|
||||
txt->qs_append(']');
|
||||
*end= data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_line_string::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
uint32 n_line_strings;
|
||||
@ -1912,6 +2508,44 @@ uint Gis_multi_polygon::init_from_opresult(String *bin,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_polygon::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_polygons= 0;
|
||||
int np_pos= wkb->length();
|
||||
Gis_polygon p;
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_rings
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
if (wkb->reserve(1 + 4, 512))
|
||||
return TRUE;
|
||||
wkb->q_append((char) wkb_ndr);
|
||||
wkb->q_append((uint32) wkb_polygon);
|
||||
|
||||
if (p.init_from_json(je, wkb))
|
||||
return TRUE;
|
||||
|
||||
n_polygons++;
|
||||
}
|
||||
wkb->write_at_position(np_pos, n_polygons);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
|
||||
{
|
||||
uint32 n_polygons;
|
||||
@ -1956,6 +2590,51 @@ bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_polygon::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_polygons;
|
||||
const char *data= m_data;
|
||||
|
||||
if (no_data(data, 4) || txt->reserve(1, 512))
|
||||
return 1;
|
||||
n_polygons= uint4korr(data);
|
||||
data+= 4;
|
||||
|
||||
txt->q_append('[');
|
||||
while (n_polygons--)
|
||||
{
|
||||
uint32 n_linear_rings;
|
||||
if (no_data(data, 4 + WKB_HEADER_SIZE) ||
|
||||
txt->reserve(1, 512))
|
||||
return 1;
|
||||
n_linear_rings= uint4korr(data+WKB_HEADER_SIZE);
|
||||
data+= 4 + WKB_HEADER_SIZE;
|
||||
txt->q_append('[');
|
||||
|
||||
while (n_linear_rings--)
|
||||
{
|
||||
if (no_data(data, 4))
|
||||
return 1;
|
||||
uint32 n_points= uint4korr(data);
|
||||
data+= 4;
|
||||
if (not_enough_points(data, n_points) ||
|
||||
txt->reserve(2 + (MAX_DIGITS_IN_DOUBLE * 2 + 6) * n_points,
|
||||
512))
|
||||
return 1;
|
||||
data= append_json_points(txt, max_dec_digits, n_points, data, 0);
|
||||
txt->qs_append(", ", 2);
|
||||
}
|
||||
txt->length(txt->length() - 2);
|
||||
txt->qs_append("], ", 3);
|
||||
}
|
||||
txt->length(txt->length() - 2);
|
||||
txt->q_append(']');
|
||||
*end= data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
uint32 n_polygons;
|
||||
@ -2304,6 +2983,47 @@ uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
|
||||
}
|
||||
|
||||
|
||||
bool Gis_geometry_collection::init_from_json(json_engine_t *je, String *wkb)
|
||||
{
|
||||
uint32 n_objects= 0;
|
||||
uint32 no_pos= wkb->length();
|
||||
Geometry_buffer buffer;
|
||||
Geometry *g;
|
||||
|
||||
if (json_read_value(je))
|
||||
return TRUE;
|
||||
|
||||
if (je->value_type != JSON_VALUE_ARRAY)
|
||||
{
|
||||
je->s.error= GEOJ_INCORRECT_GEOJSON;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wkb->reserve(4, 512))
|
||||
return TRUE;
|
||||
wkb->length(wkb->length()+4); // Reserve space for n_objects
|
||||
|
||||
while (json_scan_next(je) == 0 && je->state != JST_ARRAY_END)
|
||||
{
|
||||
json_engine_t sav_je= *je;
|
||||
|
||||
DBUG_ASSERT(je->state == JST_VALUE);
|
||||
|
||||
if (!(g= create_from_json(&buffer, je, wkb)))
|
||||
return TRUE;
|
||||
|
||||
*je= sav_je;
|
||||
if (json_skip_array_item(je))
|
||||
return TRUE;
|
||||
|
||||
n_objects++;
|
||||
}
|
||||
|
||||
wkb->write_at_position(no_pos, n_objects);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_geometry_collection::get_data_as_wkt(String *txt,
|
||||
const char **end) const
|
||||
{
|
||||
@ -2348,6 +3068,44 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const
|
||||
{
|
||||
uint32 n_objects;
|
||||
Geometry_buffer buffer;
|
||||
Geometry *geom;
|
||||
const char *data= m_data;
|
||||
|
||||
if (no_data(data, 4) || txt->reserve(1, 512))
|
||||
return 1;
|
||||
n_objects= uint4korr(data);
|
||||
data+= 4;
|
||||
|
||||
txt->qs_append('[');
|
||||
while (n_objects--)
|
||||
{
|
||||
uint32 wkb_type;
|
||||
|
||||
if (no_data(data, WKB_HEADER_SIZE))
|
||||
return 1;
|
||||
wkb_type= uint4korr(data + 1);
|
||||
data+= WKB_HEADER_SIZE;
|
||||
|
||||
if (!(geom= create_by_typeid(&buffer, wkb_type)))
|
||||
return 1;
|
||||
geom->set_data_ptr(data, (uint) (m_data_end - data));
|
||||
if (geom->as_json(txt, max_dec_digits, &data) ||
|
||||
txt->append(STRING_WITH_LEN(", "), 512))
|
||||
return 1;
|
||||
}
|
||||
txt->length(txt->length() - 2);
|
||||
txt->qs_append(']');
|
||||
|
||||
*end= data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
|
||||
{
|
||||
uint32 n_objects;
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "sql_string.h" /* String, LEX_STRING */
|
||||
#include <my_compiler.h>
|
||||
#include <json_lib.h>
|
||||
|
||||
#ifdef HAVE_SPATIAL
|
||||
|
||||
@ -249,6 +250,13 @@ public:
|
||||
wkb_xdr= 0, /* Big Endian */
|
||||
wkb_ndr= 1 /* Little Endian */
|
||||
};
|
||||
enum geojson_errors
|
||||
{
|
||||
GEOJ_INCORRECT_GEOJSON= 1,
|
||||
GEOJ_TOO_FEW_POINTS= 2,
|
||||
GEOJ_POLYGON_NOT_CLOSED= 3,
|
||||
};
|
||||
|
||||
|
||||
/** Callback which creates Geometry objects on top of a given placement. */
|
||||
typedef Geometry *(*create_geom_t)(char *);
|
||||
@ -271,8 +279,11 @@ public:
|
||||
virtual uint init_from_opresult(String *bin,
|
||||
const char *opres, uint res_len)
|
||||
{ return init_from_wkb(opres + 4, UINT_MAX32, wkb_ndr, bin) + 4; }
|
||||
virtual bool init_from_json(json_engine_t *je, String *wkb) {return true;}
|
||||
|
||||
virtual bool get_data_as_wkt(String *txt, const char **end) const=0;
|
||||
virtual bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const=0;
|
||||
virtual bool get_mbr(MBR *mbr, const char **end) const=0;
|
||||
virtual bool dimension(uint32 *dim, const char **end) const=0;
|
||||
virtual int get_x(double *x) const { return -1; }
|
||||
@ -302,9 +313,12 @@ public:
|
||||
bool init_stream=1);
|
||||
static Geometry *create_from_wkb(Geometry_buffer *buffer,
|
||||
const char *wkb, uint32 len, String *res);
|
||||
static Geometry *create_from_json(Geometry_buffer *buffer,
|
||||
json_engine_t *je, String *res);
|
||||
static Geometry *create_from_opresult(Geometry_buffer *g_buf,
|
||||
String *res, Gcalc_result_receiver &rr);
|
||||
int as_wkt(String *wkt, const char **end);
|
||||
int as_json(String *wkt, uint max_dec_digits, const char **end);
|
||||
|
||||
inline void set_data_ptr(const char *data, uint32 data_len)
|
||||
{
|
||||
@ -379,7 +393,10 @@ public:
|
||||
uint32 get_data_size() const;
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
|
||||
int get_xy(double *x, double *y) const
|
||||
@ -431,7 +448,10 @@ public:
|
||||
uint32 get_data_size() const;
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int geom_length(double *len, const char **end) const;
|
||||
int area(double *ar, const char **end) const;
|
||||
@ -462,7 +482,10 @@ public:
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
uint init_from_opresult(String *bin, const char *opres, uint res_len);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int area(double *ar, const char **end) const;
|
||||
int exterior_ring(String *result) const;
|
||||
@ -496,7 +519,10 @@ public:
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
uint init_from_opresult(String *bin, const char *opres, uint res_len);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int num_geometries(uint32 *num) const;
|
||||
int geometry_n(uint32 num, String *result) const;
|
||||
@ -522,7 +548,10 @@ public:
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
uint init_from_opresult(String *bin, const char *opres, uint res_len);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int num_geometries(uint32 *num) const;
|
||||
int geometry_n(uint32 num, String *result) const;
|
||||
@ -549,7 +578,10 @@ public:
|
||||
uint32 get_data_size() const;
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int num_geometries(uint32 *num) const;
|
||||
int geometry_n(uint32 num, String *result) const;
|
||||
@ -578,7 +610,10 @@ public:
|
||||
bool init_from_wkt(Gis_read_stream *trs, String *wkb);
|
||||
uint init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res);
|
||||
uint init_from_opresult(String *bin, const char *opres, uint res_len);
|
||||
bool init_from_json(json_engine_t *je, String *wkb);
|
||||
bool get_data_as_wkt(String *txt, const char **end) const;
|
||||
bool get_data_as_json(String *txt, uint max_dec_digits,
|
||||
const char **end) const;
|
||||
bool get_mbr(MBR *mbr, const char **end) const;
|
||||
int area(double *ar, const char **end) const;
|
||||
int geom_length(double *len, const char **end) const;
|
||||
|
@ -1231,10 +1231,7 @@ int json_key_matches(json_engine_t *je, json_string_t *k)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (json_read_string_const_chr(k))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return json_read_string_const_chr(k);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user