diff --git a/mysql-test/main/gis.result b/mysql-test/main/gis.result index d60f8da2d5d51..40c81dd9a5913 100644 --- a/mysql-test/main/gis.result +++ b/mysql-test/main/gis.result @@ -5654,3 +5654,61 @@ SELECT ST_GEOMFROMWKB (0x0104000000010000008201000000000000000000000000000000000 multipoint_bad_inner_bo NULL # End of 10.11 tests +# +# MDEV-36166 support for notation with brackets inside MULTIPOINT +# +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0))')) AS one_bracketed; +one_bracketed +MULTIPOINT(0 0) +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1))')) AS bracketed; +bracketed +MULTIPOINT(0 0,1 1) +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(0 0,1 1)')) AS bare; +bare +MULTIPOINT(0 0,1 1) +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT ( ( 0 0 ) , ( 1 1 ) )')) AS spaced; +spaced +MULTIPOINT(0 0,1 1) +SELECT ST_NUMGEOMETRIES(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1),(2 2))')) AS n; +n +3 +# The two spellings may not be mixed within one MULTIPOINT. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),1 1)')) AS mixed_open; +mixed_open +NULL +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(0 0,(1 1))')) AS mixed_close; +mixed_close +NULL +# An opened bracket must be closed after the point it opened. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0,1 1))')) AS unclosed; +unclosed +NULL +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1)')) AS truncated; +truncated +NULL +# The text may end where the first point would decide the spelling. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(')) AS ends_at_decision; +ends_at_decision +NULL +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT()')) AS empty_list; +empty_list +NULL +# Brackets around a point are a MULTIPOINT spelling only. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('LINESTRING((0 0),(1 1))')) AS linestring; +linestring +NULL +# Both spellings reach the same reader through the other WKT entries. +SELECT ST_ASTEXT(ST_MPOINTFROMTEXT('MULTIPOINT((0 0),(1 1))')) AS mpointfromtext; +mpointfromtext +MULTIPOINT(0 0,1 1) +SELECT ST_ASTEXT(ST_GEOMFROMTEXT( +'GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2)))')) AS in_collection; +in_collection +GEOMETRYCOLLECTION(MULTIPOINT(1 1,2 2)) +CREATE TABLE t1 (g GEOMETRY); +INSERT INTO t1 VALUES(ST_GEOMFROMTEXT('MULTIPOINT((1 1),(2 2))')); +SELECT ST_ASTEXT(g) FROM t1; +ST_ASTEXT(g) +MULTIPOINT(1 1,2 2) +DROP TABLE t1; +# End of 11.4 tests diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index 1efed8d076903..481740a5acf2a 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -3613,3 +3613,40 @@ SELECT ST_GEOMFROMWKB (0x0104000000010000000201000000000000000000000000000000000 SELECT ST_GEOMFROMWKB (0x0104000000010000008201000000000000000000000000000000000000000000000000) as multipoint_bad_inner_bo; --echo # End of 10.11 tests + +--echo # +--echo # MDEV-36166 support for notation with brackets inside MULTIPOINT +--echo # + +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0))')) AS one_bracketed; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1))')) AS bracketed; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(0 0,1 1)')) AS bare; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT ( ( 0 0 ) , ( 1 1 ) )')) AS spaced; +SELECT ST_NUMGEOMETRIES(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1),(2 2))')) AS n; + +--echo # The two spellings may not be mixed within one MULTIPOINT. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),1 1)')) AS mixed_open; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(0 0,(1 1))')) AS mixed_close; + +--echo # An opened bracket must be closed after the point it opened. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0,1 1))')) AS unclosed; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT((0 0),(1 1)')) AS truncated; + +--echo # The text may end where the first point would decide the spelling. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT(')) AS ends_at_decision; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('MULTIPOINT()')) AS empty_list; + +--echo # Brackets around a point are a MULTIPOINT spelling only. +SELECT ST_ASTEXT(ST_GEOMFROMTEXT('LINESTRING((0 0),(1 1))')) AS linestring; + +--echo # Both spellings reach the same reader through the other WKT entries. +SELECT ST_ASTEXT(ST_MPOINTFROMTEXT('MULTIPOINT((0 0),(1 1))')) AS mpointfromtext; +SELECT ST_ASTEXT(ST_GEOMFROMTEXT( + 'GEOMETRYCOLLECTION(MULTIPOINT((1 1),(2 2)))')) AS in_collection; + +CREATE TABLE t1 (g GEOMETRY); +INSERT INTO t1 VALUES(ST_GEOMFROMTEXT('MULTIPOINT((1 1),(2 2))')); +SELECT ST_ASTEXT(g) FROM t1; +DROP TABLE t1; + +--echo # End of 11.4 tests diff --git a/sql/spatial.cc b/sql/spatial.cc index 1484ae3d32297..e35ed645ef5fc 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -2164,18 +2164,33 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) uint32 n_points= 0; uint32 np_pos= wkb->length(); Gis_point p; + char next_sym; if (wkb->reserve(4, 512)) return 1; wkb->length(wkb->length()+4); // Reserve space for points + /* + MULTIPOINT(0 0,1 1) and MULTIPOINT((0 0),(1 1)) name the same geometry. + The first point fixes which of the two spellings the whole list uses, + and every later point repeats it. A mixed list such as + MULTIPOINT((0 0),1 1) is rejected. No check tests for mixing itself. + The point that breaks the pattern fails to parse under the spelling + already fixed. + */ + if (!(next_sym= trs->next_symbol())) + return 1; + const bool bracketed= next_sym == '('; + for (;;) { if (wkb->reserve(1 + 4, 512)) return 1; wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_point); - if (p.init_from_wkt(trs, wkb)) + if ((bracketed && trs->check_next_symbol('(')) || + p.init_from_wkt(trs, wkb) || + (bracketed && trs->check_next_symbol(')'))) return 1; n_points++; if (trs->skip_char(',')) // Didn't find ','