Commit 3830fe79 authored by Stefano Petrilli's avatar Stefano Petrilli Committed by Sergei Golubchik

MDEV-34278: Implement the GIS function ST_Collect

The GIS function ST_Collect takes as input multiple geometries and
returns the aggregation of the distinct geometry arguments.
The resulting value type is choosen using the following policy:
  - If all arguments are Point values, the result is a MultiPoint value.
  - If all arguments are LineString values, the result is a
    MultiLineString value.
  - If all arguments are Polygon values, the result is a MultiPolygon
    value.
  - Otherwise, the result is a GeometryCollection value.

If there are multiple geometry arguments and those arguments are in the
same SRS, the return value is in that SRS. If those arguments are not
in the same SRS, an ER_GIS_DIFFERENT_SRIDS_AGGREGATION error occurs.

Author: StefanoPetrilli <stefanop_1999@hotmail.it>
Co-authored-by: default avatarTorje Digernes <torje.digernes@oracle.com>
Co-authored-by: default avatarSteinar H. Gunderson <steinar.gunderson@oracle.com>
parent 6291ea11
# setup of data for tests involving simple aggregations and group by
CREATE TABLE table_simple_aggregation ( running_number INTEGER NOT NULL
AUTO_INCREMENT, grouping_condition INTEGER, location GEOMETRY , PRIMARY KEY (
running_number));
INSERT INTO table_simple_aggregation ( grouping_condition, location ) VALUES
( 0,ST_GEOMFROMTEXT('POINT(0 0)',4326)),
( 1,ST_GEOMFROMTEXT('POINT(0 0)',4326)),
( 0,ST_GEOMFROMTEXT('POINT(1 0)',4326)),
( 1,ST_GEOMFROMTEXT('POINT(2 0)',4326)),
( 0,ST_GEOMFROMTEXT('POINT(3 0)',4326));
# Functional requirement F-4: ST_COLLECT shall support simple table
# aggregations
# result shall be 1
SELECT ST_EQUALS( (SELECT ST_COLLECT( location ) AS t FROM
table_simple_aggregation) , ST_GEOMFROMTEXT('MULTIPOINT(0 0,0 0,1 0,2
0,3 0) ',4326));
ST_EQUALS( (SELECT ST_COLLECT( location ) AS t FROM
table_simple_aggregation) , ST_GEOMFROMTEXT('MULTIPOINT(0 0,0 0,1 0,2
0,3 0) ',4326))
1
INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL);
# F-7 Aggregations with Nulls inside will just miss an element for each
# Null
# the result here shall be 1
SELECT ST_EQUALS((SELECT ST_COLLECT(LOCATION) AS T FROM
table_simple_aggregation), ST_GEOMFROMTEXT('GEOMETRYCOLLECTION( MULTIPOINT(0
0,1 0,3 0), MULTIPOINT(2 0,0 0), POINT(0 0))',4326));
ST_EQUALS((SELECT ST_COLLECT(LOCATION) AS T FROM
table_simple_aggregation), ST_GEOMFROMTEXT('GEOMETRYCOLLECTION( MULTIPOINT(0
0,1 0,3 0), MULTIPOINT(2 0,0 0), POINT(0 0))',4326))
1
# F-1 ST_COLLECT SHALL only return NULL if all elements are NULL or the
# aggregate is empty.
# as only a null is aggregated the result of the subquery shall be NULL
# and the result of the whole query shall be 1
SELECT (SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
location = NULL) IS NULL;
(SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
location = NULL) IS NULL
1
# as no element is aggregated the result of the subquery shall be NULL
# and the result of the whole query shall be 1
SELECT (SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
st_srid(location)=2110) IS NULL;
(SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
st_srid(location)=2110) IS NULL
1
INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL),
( NULL);
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ROWS BETWEEN 1 PRECEDING AND
CURRENT ROW)) FROM table_simple_aggregation;
ST_ASTEXT(ST_COLLECT(location) OVER ( ROWS BETWEEN 1 PRECEDING AND
CURRENT ROW))
MULTIPOINT(0 0)
MULTIPOINT(0 0,0 0)
MULTIPOINT(0 0,1 0)
MULTIPOINT(1 0,2 0)
MULTIPOINT(2 0,3 0)
MULTIPOINT(3 0,0 -0)
MULTIPOINT(0 -0)
MULTIPOINT(0 -0)
MULTIPOINT(0 -0)
NULL
set session group_concat_max_len= 10;
SELECT ST_COLLECT( location ) AS t FROM table_simple_aggregation;
t
NULL
Warnings:
Warning 1260 Row 1 was cut by st_collect()
set session group_concat_max_len= 1048576;
# Teardown of testing NULL data
DROP TABLE table_simple_aggregation;
# Setup for testing handling of multiple SRS
CREATE TABLE multi_srs_table ( running_number INTEGER NOT NULL AUTO_INCREMENT,
geometry GEOMETRY , PRIMARY KEY ( running_number ));
INSERT INTO multi_srs_table( geometry ) VALUES
(ST_GEOMFROMTEXT('POINT(60 -24)' ,4326)),
(ST_GEOMFROMTEXT('POINT(61 -24)' ,4326)),
(ST_GEOMFROMTEXT('POINT(38 77)'));
# F-2 a) If the elements in an aggregate is of different SRSs,
# ST_COLLECT MUST raise ER_GIS_DIFFERENT_SRIDS.
SELECT ST_ASTEXT(ST_COLLECT(geometry)) AS t FROM multi_srs_table;
ERROR HY000: Arguments to function st_collect( contains geometries with different SRIDs: 4326 and 0. All geometries must have the same SRID.
#teardown of testing handling of multiple SRS
DROP TABLE multi_srs_table;
# setup of testing handling different geometry types
CREATE TABLE simple_table ( running_number INTEGER NOT NULL AUTO_INCREMENT ,
geo GEOMETRY, PRIMARY KEY ( RUNNING_NUMBER));
INSERT INTO simple_table ( geo) VALUES
(ST_GEOMFROMTEXT('POINT(0 0)')),
(ST_GEOMFROMTEXT('LINESTRING(1 0, 1 1)')),
(ST_GEOMFROMTEXT('LINESTRING(2 0, 2 1)')),
(ST_GEOMFROMTEXT('POLYGON((3 0, 0 0, 0 3, 3 3, 3 0))')),
(ST_GEOMFROMTEXT('POLYGON((4 0, 0 0, 0 4, 4 4, 4 0))')),
(ST_GEOMFROMTEXT('MULTIPOINT(5 0)')),
(ST_GEOMFROMTEXT('MULTIPOINT(6 0)')),
(ST_GEOMFROMTEXT('GEOMETRYCOLLECTION EMPTY')),
(ST_GEOMFROMTEXT('GEOMETRYCOLLECTION EMPTY'));
# Functional requirement F-9 a, b, and c ) An aggregation containing
# more than one type of geometry or any MULTI is GEOMETRYCOLLECTION, if
# it only contains a single type of POINTS, LINESTRINGS or POLYGONS it
# will be a MULTI of the same kind.
# MP: Multipoint
# MPoly: Multipolygon
# MLS: Multilinestring
# GC: geometrycollection
# Functional requirement F-6 shall support window functions
# result is expected for come in this order: MP, GC, MLS, GC, MPpoly,
# GC, GC, GC, GC
SELECT ST_ASTEXT(ST_COLLECT(geo) OVER( ORDER BY running_number ROWS BETWEEN 1
PRECEDING AND CURRENT ROW)) AS geocollect FROM simple_table;
geocollect
MULTIPOINT(0 0)
GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(1 0,1 1))
MULTILINESTRING((1 0,1 1),(2 0,2 1))
GEOMETRYCOLLECTION(LINESTRING(2 0,2 1),POLYGON((3 0,0 0,0 3,3 3,3 0)))
MULTIPOLYGON(((3 0,0 0,0 3,3 3,3 0)),((4 0,0 0,0 4,4 4,4 0)))
GEOMETRYCOLLECTION(POLYGON((4 0,0 0,0 4,4 4,4 0)),MULTIPOINT(5 0))
GEOMETRYCOLLECTION(MULTIPOINT(5 0),MULTIPOINT(6 0))
GEOMETRYCOLLECTION(MULTIPOINT(6 0),GEOMETRYCOLLECTION EMPTY)
GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY,GEOMETRYCOLLECTION EMPTY)
DROP TABLE simple_table;
# Copyright (c) 2021, Oracle and/or its affiliates
# Copyright (c) 2024, MariaDB Corporation.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
# This test is for the ST_COLLECT aggregation function, introduced in WL#13454
--echo # setup of data for tests involving simple aggregations and group by
CREATE TABLE table_simple_aggregation ( running_number INTEGER NOT NULL
AUTO_INCREMENT, grouping_condition INTEGER, location GEOMETRY , PRIMARY KEY (
running_number));
INSERT INTO table_simple_aggregation ( grouping_condition, location ) VALUES
( 0,ST_GEOMFROMTEXT('POINT(0 0)',4326)),
( 1,ST_GEOMFROMTEXT('POINT(0 0)',4326)),
( 0,ST_GEOMFROMTEXT('POINT(1 0)',4326)),
( 1,ST_GEOMFROMTEXT('POINT(2 0)',4326)),
( 0,ST_GEOMFROMTEXT('POINT(3 0)',4326));
--echo # Functional requirement F-4: ST_COLLECT shall support simple table
--echo # aggregations
--echo # result shall be 1
SELECT ST_EQUALS( (SELECT ST_COLLECT( location ) AS t FROM
table_simple_aggregation) , ST_GEOMFROMTEXT('MULTIPOINT(0 0,0 0,1 0,2
0,3 0) ',4326));
# --echo # Functional requirement F-8 Shall support DISTINCT in aggregates
# --echo # result shall be 1
# SELECT ST_EQUALS( (SELECT ST_COLLECT( DISTINCT location ) AS t FROM
# table_simple_aggregation) , ST_GEOMFROMTEXT('MULTIPOINT(0 0,1 0,2 0,3
# 0) ',4326));
# --echo # Functional requirement F-5: ST_COLLECT shall support group by, which
# --echo # is given by aggregation machinery
# --echo # result shall be
# --echo # MULTIPOINT(0 0,1 0,3 0)
# --echo # MULTIPOINT(2 0,0 0)
# --sorted_result
# SELECT ST_ASTEXT(ST_COLLECT( DISTINCT location )) AS t FROM
# table_simple_aggregation GROUP BY grouping_condition;
# --echo # Distinct with rollup
# SELECT st_astext(ST_COLLECT( distinct location )) AS t from
# table_simple_aggregation group by st_latitude(location) with rollup;
INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL);
--echo # F-7 Aggregations with Nulls inside will just miss an element for each
--echo # Null
--echo # the result here shall be 1
SELECT ST_EQUALS((SELECT ST_COLLECT(LOCATION) AS T FROM
table_simple_aggregation), ST_GEOMFROMTEXT('GEOMETRYCOLLECTION( MULTIPOINT(0
0,1 0,3 0), MULTIPOINT(2 0,0 0), POINT(0 0))',4326));
--echo # F-1 ST_COLLECT SHALL only return NULL if all elements are NULL or the
--echo # aggregate is empty.
--echo # as only a null is aggregated the result of the subquery shall be NULL
--echo # and the result of the whole query shall be 1
SELECT (SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
location = NULL) IS NULL;
--echo # as no element is aggregated the result of the subquery shall be NULL
--echo # and the result of the whole query shall be 1
SELECT (SELECT ST_COLLECT(location) AS t FROM table_simple_aggregation WHERE
st_srid(location)=2110) IS NULL;
INSERT INTO table_simple_aggregation (location) VALUES
( ST_GEOMFROMTEXT('POINT(0 -0)' ,4326)),
( NULL),
( NULL);
SELECT ST_ASTEXT(ST_COLLECT(location) OVER ( ROWS BETWEEN 1 PRECEDING AND
CURRENT ROW)) FROM table_simple_aggregation;
# --echo Excercising multiple code paths.
# --sorted_result
# SELECT ST_ASTEXT(ST_COLLECT(DISTINCT location)) AS geo, SUM(running_number)
# OVER() FROM table_simple_aggregation GROUP BY running_number;
# --sorted_result
# SELECT ST_ASTEXT(ST_COLLECT(DISTINCT location)) AS geo, SUM(grouping_condition)
# OVER(), grouping_condition FROM table_simple_aggregation GROUP BY
# grouping_condition;
# --sorted_result
# SELECT ST_ASTEXT(ST_COLLECT(location)) AS geo, SUM(grouping_condition) OVER(),
# grouping_condition FROM table_simple_aggregation GROUP BY grouping_condition;
# --sorted_result
# SELECT ST_ASTEXT(ST_COLLECT(location)) AS geo, SUM(running_number) OVER() FROM
# table_simple_aggregation GROUP BY running_number;
--enable_warnings
set session group_concat_max_len= 10;
SELECT ST_COLLECT( location ) AS t FROM table_simple_aggregation;
set session group_concat_max_len= 1048576;
--disable_warnings
--echo # Teardown of testing NULL data
DROP TABLE table_simple_aggregation;
--echo # Setup for testing handling of multiple SRS
CREATE TABLE multi_srs_table ( running_number INTEGER NOT NULL AUTO_INCREMENT,
geometry GEOMETRY , PRIMARY KEY ( running_number ));
INSERT INTO multi_srs_table( geometry ) VALUES
(ST_GEOMFROMTEXT('POINT(60 -24)' ,4326)),
(ST_GEOMFROMTEXT('POINT(61 -24)' ,4326)),
(ST_GEOMFROMTEXT('POINT(38 77)'));
--echo # F-2 a) If the elements in an aggregate is of different SRSs,
--echo # ST_COLLECT MUST raise ER_GIS_DIFFERENT_SRIDS.
--error ER_GIS_DIFFERENT_SRIDS_AGGREGATION
SELECT ST_ASTEXT(ST_COLLECT(geometry)) AS t FROM multi_srs_table;
# TODO fix this
# --echo # F-2 b) If all the elements in an aggregate is of same SRS, ST_COLLECT
# --echo # MUST return a result in that SRS.
# --echo # result shall be one MULTIPOINT((60 -24),(61 -24)) with SRID 4326 and
# --echo # one
# --echo # Multipoint((38 77)) with SRID 0. There is some rounding issue on the
# --echo # result, bug #31535105
# --sorted_result
# SELECT st_srid(geometry),ST_ASTEXT(ST_COLLECT( geometry )) AS t FROM
# multi_srs_table GROUP BY ST_SRID(geometry);
# --echo Rollup needs all SRIDs to be the same.
# --error ER_GIS_DIFFERENT_SRIDS_AGGREGATION
# SELECT st_srid(geometry),ST_ASTEXT(ST_COLLECT( geometry )) AS t FROM
# multi_srs_table GROUP BY ST_SRID(geometry) WITH ROLLUP;
# --echo # Triggering a codepath for geometrycollection in temp tables
# INSERT INTO multi_srs_table( geometry ) VALUES
# (ST_GEOMFROMTEXT('GEOMETRYCOLLECTION(POINT(60 -24))' ,4326));
# --sorted_result
# SELECT st_srid(geometry),ST_ASTEXT(ST_COLLECT( geometry )) AS t FROM
# multi_srs_table GROUP BY ST_SRID(geometry);
--echo #teardown of testing handling of multiple SRS
DROP TABLE multi_srs_table;
--echo # setup of testing handling different geometry types
CREATE TABLE simple_table ( running_number INTEGER NOT NULL AUTO_INCREMENT ,
geo GEOMETRY, PRIMARY KEY ( RUNNING_NUMBER));
INSERT INTO simple_table ( geo) VALUES
(ST_GEOMFROMTEXT('POINT(0 0)')),
(ST_GEOMFROMTEXT('LINESTRING(1 0, 1 1)')),
(ST_GEOMFROMTEXT('LINESTRING(2 0, 2 1)')),
(ST_GEOMFROMTEXT('POLYGON((3 0, 0 0, 0 3, 3 3, 3 0))')),
(ST_GEOMFROMTEXT('POLYGON((4 0, 0 0, 0 4, 4 4, 4 0))')),
(ST_GEOMFROMTEXT('MULTIPOINT(5 0)')),
(ST_GEOMFROMTEXT('MULTIPOINT(6 0)')),
(ST_GEOMFROMTEXT('GEOMETRYCOLLECTION EMPTY')),
(ST_GEOMFROMTEXT('GEOMETRYCOLLECTION EMPTY'));
--echo # Functional requirement F-9 a, b, and c ) An aggregation containing
--echo # more than one type of geometry or any MULTI is GEOMETRYCOLLECTION, if
--echo # it only contains a single type of POINTS, LINESTRINGS or POLYGONS it
--echo # will be a MULTI of the same kind.
--echo # MP: Multipoint
--echo # MPoly: Multipolygon
--echo # MLS: Multilinestring
--echo # GC: geometrycollection
--echo # Functional requirement F-6 shall support window functions
--echo # result is expected for come in this order: MP, GC, MLS, GC, MPpoly,
--echo # GC, GC, GC, GC
SELECT ST_ASTEXT(ST_COLLECT(geo) OVER( ORDER BY running_number ROWS BETWEEN 1
PRECEDING AND CURRENT ROW)) AS geocollect FROM simple_table;
# --echo # with DISTINCT this result is expected to be:
# --echo # GEMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)
# --echo # GEMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)
# SELECT ST_ASTEXT(ST_COLLECT( DISTINCT geo) OVER( ORDER BY running_number ROWS
# BETWEEN 1 PRECEDING AND CURRENT ROW)) AS geocollect FROM simple_table WHERE
# ST_EQUALS(geo,ST_GEOMFROMTEXT('GEOMETRYCOLLECTION EMPTY'));
# --echo # Exercising the "copy" constructor
# SELECT ST_ASTEXT(ST_COLLECT(geo)) FROM simple_table GROUP BY geo WITH ROLLUP;
# --echo # Casting Geometry as decimal invokes val_decimal()
# SELECT CAST(ST_COLLECT(geo) AS DECIMAL ) FROM simple_table;
DROP TABLE simple_table;
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "sp.h" #include "sp.h"
#include "sql_parse.h" #include "sql_parse.h"
#include "sp_head.h" #include "sp_head.h"
#include "item_sum.h"
/** /**
Calculate the affordable RAM limit for structures like TREE or Unique Calculate the affordable RAM limit for structures like TREE or Unique
...@@ -4616,5 +4617,158 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) ...@@ -4616,5 +4617,158 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
Item_func_group_concat::~Item_func_group_concat() Item_func_group_concat::~Item_func_group_concat()
{ {
if (!original && unique_filter) if (!original && unique_filter)
delete unique_filter; delete unique_filter;
}
void Item_func_collect::clear() {
has_cached_result= false;
cached_result.free();
geometries.delete_elements();
}
void Item_func_collect::cleanup() {
List_iterator<String> geometries_iterator(geometries);
geometries.delete_elements();
Item_sum_int::cleanup();
}
bool Item_func_collect::add() {
String *wkb= args[0]->val_str(&value);
uint current_geometry_srid;
has_cached_result= false;
if (tmp_arg[0]->null_value)
return 0;
current_geometry_srid= uint4korr(wkb->ptr());
if (geometries.is_empty())
srid= current_geometry_srid;
else if(srid != current_geometry_srid)
my_error(ER_GIS_DIFFERENT_SRIDS_AGGREGATION, MYF(0), func_name(), srid,
current_geometry_srid);
String* buffer= new String(wkb->length());
buffer->copy(*wkb);
geometries.push_back(buffer);
return 0;
}
void Item_func_collect::remove() {
String value;
String *wkb= args[0]->val_str(&value);
has_cached_result= false;
if (args[0]->null_value) return;
List_iterator<String> geometries_iterator(geometries);
String* temp_geometry;
while ((temp_geometry= geometries_iterator++))
{
String temp(temp_geometry->ptr(), temp_geometry->length(), &my_charset_bin);
if (!wkb->eq(&temp, &my_charset_bin))
continue;
temp_geometry->free();
delete temp_geometry;
geometries_iterator.remove();
break;
}
return;
}
Item_func_collect::Item_func_collect(THD *thd, Item *item_par) :
Item_sum_int(thd, item_par),
mem_root(thd->mem_root),
group_collect_max_len(thd->variables.group_concat_max_len)
{
}
Item_func_collect::Item_func_collect(THD *thd, Item_func_collect *item) :
Item_sum_int(thd, item),
mem_root(thd->mem_root),
group_collect_max_len(thd->variables.group_concat_max_len)
{
}
String *Item_func_collect::val_str(String *str)
{
Geometry_buffer buffer;
int type= Geometry::wkbType::wkb_last;
const int initial_type= Geometry::wkbType::wkb_last;
Geometry *geometry;
String content;
content.free();
str->free();
if (has_cached_result)
{
str->append(cached_result.ptr(), cached_result.length());
return str;
}
null_value= 1;
if (geometries.is_empty())
return NULL;
if (content.reserve(WKB_HEADER_SIZE + SRID_SIZE) ||
str->reserve(WKB_HEADER_SIZE + SRID_SIZE))
return NULL;
List_iterator<String> geometries_iterator(geometries);
String* temp_geometry;
while ((temp_geometry= geometries_iterator++))
{
if(!(geometry = Geometry::construct(&buffer, temp_geometry->ptr(),
temp_geometry->length())))
return NULL;
if (content.length() > group_collect_max_len)
{
THD *thd= current_thd;
report_cut_value_error(thd, 1, func_name());
return NULL;
}
if (type == initial_type)
{
type= geometry->get_class_info()->m_type_id;
content.append(temp_geometry->ptr() + SRID_SIZE,
temp_geometry->length() - SRID_SIZE);
continue;
}
if (type != geometry->get_class_info()->m_type_id)
type= Geometry::wkbType::wkb_geometrycollection;
content.append(temp_geometry->ptr() + SRID_SIZE,
temp_geometry->length() - SRID_SIZE);
}
str->q_append((uint32) srid);
str->q_append((char) Geometry::wkb_ndr);
str->q_append(type <= 3 ?
(uint32) type + 3 : (uint32) Geometry::wkb_geometrycollection);
str->q_append((uint32) geometries.size());
str->append(content.ptr(), content.length());
null_value= 0;
has_cached_result= true;
cached_result.free();
cached_result.append(str->ptr(), str->length());
return str;
}
Item *Item_func_collect::copy_or_same(THD *thd) {
return new (thd->mem_root) Item_func_collect(thd, this);
} }
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <my_tree.h> #include <my_tree.h>
#include "sql_udf.h" /* udf_handler */ #include "sql_udf.h" /* udf_handler */
#include "item.h"
#include "spatial.h" // Geometry_buffer, Geometry
class Item_sum; class Item_sum;
class Aggregator_distinct; class Aggregator_distinct;
...@@ -352,7 +354,7 @@ class Item_sum :public Item_func_or_sum ...@@ -352,7 +354,7 @@ class Item_sum :public Item_func_or_sum
CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC, CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC,
NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC, NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC,
PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC, JSON_ARRAYAGG_FUNC, PERCENTILE_DISC_FUNC, SP_AGGREGATE_FUNC, JSON_ARRAYAGG_FUNC,
JSON_OBJECTAGG_FUNC JSON_OBJECTAGG_FUNC, GEOMETRY_COLLECT_FUNC
}; };
Item **ref_by; /* pointer to a ref to the object used to register it */ Item **ref_by; /* pointer to a ref to the object used to register it */
...@@ -433,6 +435,7 @@ class Item_sum :public Item_func_or_sum ...@@ -433,6 +435,7 @@ class Item_sum :public Item_func_or_sum
case UDF_SUM_FUNC: case UDF_SUM_FUNC:
case GROUP_CONCAT_FUNC: case GROUP_CONCAT_FUNC:
case JSON_ARRAYAGG_FUNC: case JSON_ARRAYAGG_FUNC:
case GEOMETRY_COLLECT_FUNC:
return true; return true;
default: default:
return false; return false;
...@@ -2115,4 +2118,52 @@ class Item_func_group_concat : public Item_sum ...@@ -2115,4 +2118,52 @@ class Item_func_group_concat : public Item_sum
}; };
class Item_func_collect :public Item_sum_int
{
uint32 srid;
bool has_cached_result;
String cached_result;
MEM_ROOT *mem_root;
List<String> geometries;
String value;
const uint group_collect_max_len;
void clear() override;
bool add() override;
void cleanup() override;
void remove() override;
public:
Item_func_collect(THD *thd, Item *item_par);
Item_func_collect(THD *thd, Item_func_collect *item);
enum Sumfunctype sum_func () const override
{
return GEOMETRY_COLLECT_FUNC;
}
void no_rows_in_result() override {; }
void make_const(longlong count_arg)
{
Item_sum_int::make_const();
}
const Type_handler *type_handler() const override
{ return &type_handler_string; }
longlong val_int() override { return 0; }
String *val_str(String*str) override;
void reset_field() override {DBUG_ASSERT(0);}
void update_field() override {DBUG_ASSERT(0);}
LEX_CSTRING func_name_cstring() const override
{
return { STRING_WITH_LEN("st_collect(") };
}
Item *copy_or_same(THD* thd) override;
Item *do_get_copy(THD *thd) const override
{ return get_item_copy<Item_func_collect>(thd, this); }
bool supports_removal() const override
{
return true;
}
};
#endif /* ITEM_SUM_INCLUDED */ #endif /* ITEM_SUM_INCLUDED */
...@@ -788,6 +788,7 @@ SYMBOL sql_functions[] = { ...@@ -788,6 +788,7 @@ SYMBOL sql_functions[] = {
{ "STDDEV", SYM(STD_SYM)}, { "STDDEV", SYM(STD_SYM)},
{ "STDDEV_POP", SYM(STD_SYM)}, { "STDDEV_POP", SYM(STD_SYM)},
{ "STDDEV_SAMP", SYM(STDDEV_SAMP_SYM)}, { "STDDEV_SAMP", SYM(STDDEV_SAMP_SYM)},
{ "ST_COLLECT", SYM(ST_COLLECT_SYM)},
{ "SUBDATE", SYM(SUBDATE_SYM)}, { "SUBDATE", SYM(SUBDATE_SYM)},
{ "SUBSTR", SYM(SUBSTRING)}, { "SUBSTR", SYM(SUBSTRING)},
{ "SUBSTRING", SYM(SUBSTRING)}, { "SUBSTRING", SYM(SUBSTRING)},
......
...@@ -12297,3 +12297,5 @@ ER_LONGITUDE_OUT_OF_RANGE ...@@ -12297,3 +12297,5 @@ ER_LONGITUDE_OUT_OF_RANGE
eng "Longitude %f is out of range in function %s. It must be within (-180.000000, 180.000000]." eng "Longitude %f is out of range in function %s. It must be within (-180.000000, 180.000000]."
ER_LATITUDE_OUT_OF_RANGE ER_LATITUDE_OUT_OF_RANGE
eng "Latitude %f is out of range in function %s. It must be within [-90.000000, 90.000000]." eng "Latitude %f is out of range in function %s. It must be within [-90.000000, 90.000000]."
ER_GIS_DIFFERENT_SRIDS_AGGREGATION
eng "Arguments to function %s contains geometries with different SRIDs: %d and %d. All geometries must have the same SRID."
...@@ -152,6 +152,7 @@ class base_list :public Sql_alloc ...@@ -152,6 +152,7 @@ class base_list :public Sql_alloc
return *this; return *this;
} }
inline uint size() { return elements; }
inline void empty() { elements=0; first= &end_of_list; last=&first;} inline void empty() { elements=0; first= &end_of_list; last=&first;}
inline base_list() { empty(); } inline base_list() { empty(); }
/** /**
......
...@@ -1180,7 +1180,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1180,7 +1180,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> XA_SYM %token <kwd> XA_SYM
%token <kwd> XML_SYM %token <kwd> XML_SYM
%token <kwd> YEAR_SYM /* SQL-2003-R */ %token <kwd> YEAR_SYM /* SQL-2003-R */
%token <kwd> ST_COLLECT_SYM
/* A dummy token to force the priority of table_ref production in a join. */ /* A dummy token to force the priority of table_ref production in a join. */
%left CONDITIONLESS_JOIN %left CONDITIONLESS_JOIN
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING %left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT ON_SYM USING
...@@ -11149,6 +11149,12 @@ sum_expr: ...@@ -11149,6 +11149,12 @@ sum_expr:
if (unlikely($$ == NULL)) if (unlikely($$ == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| ST_COLLECT_SYM '(' in_sum_expr ')'
{
$$= new (thd->mem_root) Item_func_collect(thd, $3);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
; ;
window_func_expr: window_func_expr:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment