From: Sandro Santilli Date: Fri, 20 Jan 2012 14:47:36 +0000 (+0000) Subject: Have TopoGeometry::Geometry always return a MULTI* (#1462) X-Git-Tag: 2.0.0alpha2~28 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4349de763e997ea0ac864bf59c19429676b7687c;p=postgis Have TopoGeometry::Geometry always return a MULTI* (#1462) git-svn-id: http://svn.osgeo.org/postgis/trunk@8893 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/topology/test/regress/createtopogeom_expected b/topology/test/regress/createtopogeom_expected index 95af83eb5..a6102229f 100644 --- a/topology/test/regress/createtopogeom_expected +++ b/topology/test/regress/createtopogeom_expected @@ -13,20 +13,20 @@ l2|2 n2|2 e1|1 ERROR: A TopoGeometry of type 2 cannot contain topology elements of type 1 -L1|LINESTRING(0 0,10 0) +L1|MULTILINESTRING((0 0,10 0)) l3|3 e2|2 f1|1 ERROR: A Layer of type 3 cannot contain a TopoGeometry of type 2 ERROR: A TopoGeometry of type 3 cannot contain topology elements of type 2 -A1|POLYGON((10 0,0 0,5 5,10 0)) +A1|MULTIPOLYGON(((10 0,0 0,5 5,10 0))) l4|4 -MP|POINT(0 0) -ML|LINESTRING(0 0,10 0) -MA|POLYGON((10 0,0 0,5 5,10 0)) +MP|MULTIPOINT(0 0) +ML|MULTILINESTRING((0 0,10 0)) +MA|MULTIPOLYGON(((10 0,0 0,5 5,10 0))) MM|GEOMETRYCOLLECTION(POLYGON((10 0,0 0,5 5,10 0)),LINESTRING(0 0,10 0),POINT(0 0)) -POINT EMPTY|POINT EMPTY -LINESTRING EMPTY|LINESTRING EMPTY -POLYGON EMPTY|POLYGON EMPTY +POINT EMPTY|MULTIPOINT EMPTY +LINESTRING EMPTY|MULTILINESTRING EMPTY +POLYGON EMPTY|MULTIPOLYGON EMPTY GEOMETRYCOLLECTION EMPTY|GEOMETRYCOLLECTION EMPTY Topology 'MiX' dropped diff --git a/topology/test/regress/legacy_query_expected b/topology/test/regress/legacy_query_expected index 2c80da1a1..e92a2402f 100644 --- a/topology/test/regress/legacy_query_expected +++ b/topology/test/regress/legacy_query_expected @@ -15,36 +15,36 @@ features.big_parcels.the_geom SRID:0 TYPE:MULTIPOLYGON DIMS:2 6 features.big_signs.the_geom SRID:0 TYPE:MULTIPOINT DIMS:2 BEGIN -P1|1|POLYGON((21 14,21 6,9 6,9 14,9 22,21 22,21 14)) -P2|2|POLYGON((35 14,35 6,21 6,21 14,21 22,35 22,35 14)) -P3|3|POLYGON((47 14,47 6,35 6,35 14,35 22,47 22,47 14)) -P4|4|POLYGON((25 30,17 30,17 40,31 40,31 30,25 30)) -P5|5|POLYGON((8 30,3 30,3 38,16 38,16 30,8 30),(4 31,7 31,7 34,4 34,4 31)) -F3|6|POLYGON((9 22,21 22,21 14,9 14,9 22)) -F6|7|POLYGON((9 14,21 14,21 6,9 6,9 14)) -F3F4|8|POLYGON((9 22,21 22,35 22,35 14,21 14,9 14,9 22)) -F1|9|POLYGON((8 30,3 30,3 38,16 38,16 30,8 30),(4 31,7 31,7 34,4 34,4 31)) -S1|1|POINT(21 14) -S2|2|POINT(35 14) -S3|3|POINT(57 33) -S4|4|POINT(20 37) +P1|1|MULTIPOLYGON(((21 14,21 6,9 6,9 14,9 22,21 22,21 14))) +P2|2|MULTIPOLYGON(((35 14,35 6,21 6,21 14,21 22,35 22,35 14))) +P3|3|MULTIPOLYGON(((47 14,47 6,35 6,35 14,35 22,47 22,47 14))) +P4|4|MULTIPOLYGON(((25 30,17 30,17 40,31 40,31 30,25 30))) +P5|5|MULTIPOLYGON(((8 30,3 30,3 38,16 38,16 30,8 30),(4 31,7 31,7 34,4 34,4 31))) +F3|6|MULTIPOLYGON(((9 22,21 22,21 14,9 14,9 22))) +F6|7|MULTIPOLYGON(((9 14,21 14,21 6,9 6,9 14))) +F3F4|8|MULTIPOLYGON(((9 22,21 22,35 22,35 14,21 14,9 14,9 22))) +F1|9|MULTIPOLYGON(((8 30,3 30,3 38,16 38,16 30,8 30),(4 31,7 31,7 34,4 34,4 31))) +S1|1|MULTIPOINT(21 14) +S2|2|MULTIPOINT(35 14) +S3|3|MULTIPOINT(57 33) +S4|4|MULTIPOINT(20 37) N1N2N3|5|MULTIPOINT(8 30,25 30,25 35) N1N6N14|6|MULTIPOINT(8 30,21 14,57 33) N3N4|7|MULTIPOINT(20 37,25 35) -N4|8|POINT(20 37) -R1|1|LINESTRING(9 14,21 14,35 14) -R2|2|LINESTRING(36 38,38 35,41 34,42 33,45 32,47 28,50 28,52 32,57 33,57 36,59 39,61 38,62 41,47 42,45 40,41 40) -R3|3|LINESTRING(9 35,13 35) -R4|4|LINESTRING(25 30,25 35) -E7E8|5|LINESTRING(21 22,35 22,47 22) -E20E19|6|LINESTRING(21 6,21 14,21 22) -E25|7|LINESTRING(9 35,13 35) -R1a|8|LINESTRING(9 14,21 14,35 14) +N4|8|MULTIPOINT(20 37) +R1|1|MULTILINESTRING((9 14,21 14,35 14)) +R2|2|MULTILINESTRING((36 38,38 35,41 34,42 33,45 32,47 28,50 28,52 32,57 33,57 36,59 39,61 38,62 41,47 42,45 40,41 40)) +R3|3|MULTILINESTRING((9 35,13 35)) +R4|4|MULTILINESTRING((25 30,25 35)) +E7E8|5|MULTILINESTRING((21 22,35 22,47 22)) +E20E19|6|MULTILINESTRING((21 6,21 14,21 22)) +E25|7|MULTILINESTRING((9 35,13 35)) +R1a|8|MULTILINESTRING((9 14,21 14,35 14)) S1S2|MULTIPOINT(21 14,35 14) R1R2|MULTILINESTRING((36 38,38 35,41 34,42 33,45 32,47 28,50 28,52 32,57 33,57 36,59 39,61 38,62 41,47 42,45 40,41 40),(9 14,21 14,35 14)) -R4|LINESTRING(25 30,25 35) -P1P2|POLYGON((21 6,9 6,9 14,9 22,21 22,35 22,35 14,35 6,21 6)) +R4|MULTILINESTRING((25 30,25 35)) +P1P2|MULTIPOLYGON(((21 6,9 6,9 14,9 22,21 22,35 22,35 14,35 6,21 6))) P3P4|MULTIPOLYGON(((47 14,47 6,35 6,35 14,35 22,47 22,47 14)),((25 30,17 30,17 40,31 40,31 30,25 30))) -F3F6|POLYGON((21 14,21 6,9 6,9 14,9 22,21 22,21 14)) +F3F6|MULTIPOLYGON(((21 14,21 6,9 6,9 14,9 22,21 22,21 14))) COMMIT Topology 'city_data' dropped diff --git a/topology/test/regress/topo2.5d_expected b/topology/test/regress/topo2.5d_expected index 6bffb8869..0f47c1d07 100644 --- a/topology/test/regress/topo2.5d_expected +++ b/topology/test/regress/topo2.5d_expected @@ -1,6 +1,6 @@ t 1 2 -f1|POLYGON((0 0 30,0 10 25,10 10 20,10 0 18,0 0 30)) -l1|LINESTRING(0 0 30,0 10 25,10 10 20,10 0 18,0 0 30) +f1|MULTIPOLYGON(((0 0 30,0 10 25,10 10 20,10 0 18,0 0 30))) +l1|MULTILINESTRING((0 0 30,0 10 25,10 10 20,10 0 18,0 0 30)) Topology 'tt3d' dropped diff --git a/topology/test/regress/totopogeom_expected b/topology/test/regress/totopogeom_expected index ce5d19a9d..22dce3ea7 100644 --- a/topology/test/regress/totopogeom_expected +++ b/topology/test/regress/totopogeom_expected @@ -22,11 +22,11 @@ MULTIPOINT(0 -10,5 -10)|t MULTILINESTRING((-1 10,-10 10),(-10 8,-2 9))|t MULTIPOLYGON(((100 20,110 20,105 30,100 20),(102 22,108 22,105 28,102 22)),((80 20,90 20,90 60,80 20)))|t GEOMETRYCOLLECTION(POINT(-100 -100),LINESTRING(-100 -90,-90 -90),POLYGON((-100 -80,-90 -80,-95 -70,-100 -80),(-98 -78,-92 -78,-95 -72,-98 -78)),MULTIPOINT(-100 -110,-95 -110),LINESTRING EMPTY,MULTILINESTRING((-101 -90,-110 -90),(-110 -92,-102 -91)),MULTIPOLYGON(((0 -80,10 -80,5 -70,0 -80),(2 -78,8 -78,5 -72,2 -78)),((-20 -80,-10 -80,-10 -40,-20 -80))))|GEOMETRYCOLLECTION(MULTIPOLYGON(((-100 -80,-95 -70,-90 -80,-100 -80),(-98 -78,-92 -78,-95 -72,-98 -78)),((0 -80,5 -70,10 -80,0 -80),(2 -78,8 -78,5 -72,2 -78)),((-20 -80,-10 -40,-10 -80,-20 -80))),MULTILINESTRING((-110 -92,-102 -91),(-101 -90,-110 -90),(-100 -90,-90 -90)),MULTIPOINT(-100 -110,-100 -100,-95 -110)) -POINT EMPTY -POINT EMPTY -LINESTRING EMPTY -LINESTRING EMPTY -POLYGON EMPTY -POLYGON EMPTY +MULTIPOINT EMPTY +MULTIPOINT EMPTY +MULTILINESTRING EMPTY +MULTILINESTRING EMPTY +MULTIPOLYGON EMPTY +MULTIPOLYGON EMPTY GEOMETRYCOLLECTION EMPTY Topology 'tt' dropped diff --git a/topology/topology.sql.in.c b/topology/topology.sql.in.c index ef8cd57cc..ea4256f91 100644 --- a/topology/topology.sql.in.c +++ b/topology/topology.sql.in.c @@ -1167,112 +1167,98 @@ DECLARE rec RECORD; plyr RECORD; clyr RECORD; - query text; - ok BOOL; sql TEXT; BEGIN - -- Get topology name - SELECT name FROM topology.topology into toponame - WHERE id = topogeom.topology_id; - -- Get layer info - ok = false; - FOR rec IN EXECUTE 'SELECT * FROM topology.layer ' - || ' WHERE topology_id = ' || topogeom.topology_id - || ' AND layer_id = ' || topogeom.layer_id - LOOP - ok = true; - plyr = rec; - END LOOP; + -- Get topology name + SELECT name FROM topology.topology + WHERE id = topogeom.topology_id + INTO toponame; + IF toponame IS NULL THEN + RAISE EXCEPTION 'Invalid TopoGeometry (unexistent topology id %)', topogeom.topology_id; + END IF; - IF NOT ok THEN - RAISE EXCEPTION 'Could not find TopoGeometry layer % in topology %', topogeom.layer_id, topogeom.topology_id; - END IF; + -- Get layer info + SELECT * FROM topology.layer + WHERE topology_id = topogeom.topology_id + AND layer_id = topogeom.layer_id + INTO plyr; + IF plyr IS NULL THEN + RAISE EXCEPTION 'Could not find TopoGeometry layer % in topology %', topogeom.layer_id, topogeom.topology_id; + END IF; - -- - -- If this feature layer is on any level > 0 we will - -- compute the topological union of all child features - -- in fact recursing. - -- - IF plyr.level > 0 THEN - - -- Get child layer info - SELECT * INTO STRICT clyr FROM topology.layer - WHERE layer_id = plyr.child_id - AND topology_id = topogeom.topology_id; - - query = 'SELECT st_union(topology.Geometry(' - || quote_ident(clyr.feature_column) - || ')) as geom FROM ' - || quote_ident(clyr.schema_name) || '.' - || quote_ident(clyr.table_name) - || ', ' || quote_ident(toponame) || '.relation pr' - || ' WHERE ' - || ' pr.topogeo_id = ' || topogeom.id - || ' AND ' - || ' pr.layer_id = ' || topogeom.layer_id - || ' AND ' - || ' id('||quote_ident(clyr.feature_column) - || ') = pr.element_id ' - || ' AND ' - || 'layer_id('||quote_ident(clyr.feature_column) - || ') = pr.element_type '; - --RAISE DEBUG '%', query; - FOR rec IN EXECUTE query - LOOP - RETURN rec.geom; - END LOOP; - - END IF; - + -- + -- If this feature layer is on any level > 0 we will + -- compute the topological union of all child features + -- in fact recursing. + -- + IF plyr.level > 0 THEN -- { + + -- Get child layer info + SELECT * FROM topology.layer WHERE layer_id = plyr.child_id + AND topology_id = topogeom.topology_id + INTO clyr; + IF clyr IS NULL THEN + RAISE EXCEPTION 'Invalid layer % in topology % (unexistent child layer %)', topogeom.layer_id, topogeom.topology_id, plyr.child_id; + END IF; - IF topogeom.type = 3 THEN -- [multi]polygon - FOR rec IN EXECUTE 'SELECT st_union(' - || 'topology.ST_GetFaceGeometry(' - || quote_literal(toponame) || ',' - || 'element_id)) as g FROM ' - || quote_ident(toponame) - || '.relation WHERE topogeo_id = ' - || topogeom.id || ' AND layer_id = ' - || topogeom.layer_id || ' AND element_type = 3 ' - LOOP - geom := rec.g; - END LOOP; - IF geom IS NULL THEN - geom := 'POLYGON EMPTY'; - END IF; + sql := 'SELECT st_multi(st_union(topology.Geometry(' + || quote_ident(clyr.feature_column) + || '))) as geom FROM ' + || quote_ident(clyr.schema_name) || '.' + || quote_ident(clyr.table_name) + || ', ' || quote_ident(toponame) || '.relation pr' + || ' WHERE ' + || ' pr.topogeo_id = ' || topogeom.id + || ' AND ' + || ' pr.layer_id = ' || topogeom.layer_id + || ' AND ' + || ' id('||quote_ident(clyr.feature_column) + || ') = pr.element_id ' + || ' AND ' + || 'layer_id('||quote_ident(clyr.feature_column) + || ') = pr.element_type '; + --RAISE DEBUG '%', query; + EXECUTE sql INTO geom; + + ELSIF topogeom.type = 3 THEN -- [multi]polygon -- }{ - ELSIF topogeom.type = 2 THEN -- [multi]line - FOR rec IN EXECUTE 'SELECT ST_LineMerge(ST_Collect(e.geom)) as g FROM ' - || quote_ident(toponame) || '.edge e, ' - || quote_ident(toponame) || '.relation r ' - || ' WHERE r.topogeo_id = ' || topogeom.id - || ' AND r.layer_id = ' || topogeom.layer_id - || ' AND r.element_type = 2 ' - || ' AND abs(r.element_id) = e.edge_id' - LOOP - geom := rec.g; - END LOOP; - IF geom IS NULL THEN - geom := 'LINESTRING EMPTY'; - END IF; - - ELSIF topogeom.type = 1 THEN -- [multi]point - FOR rec IN EXECUTE 'SELECT st_union(n.geom) as g FROM ' - || quote_ident(toponame) || '.node n, ' - || quote_ident(toponame) || '.relation r ' - || ' WHERE r.topogeo_id = ' || topogeom.id - || ' AND r.layer_id = ' || topogeom.layer_id - || ' AND r.element_type = 1 ' - || ' AND r.element_id = n.node_id' - LOOP - geom := rec.g; - END LOOP; - IF geom IS NULL THEN - geom := 'POINT EMPTY'; - END IF; + sql := 'SELECT st_multi(st_union(' + || 'topology.ST_GetFaceGeometry(' + || quote_literal(toponame) || ',' + || 'element_id))) as g FROM ' + || quote_ident(toponame) + || '.relation WHERE topogeo_id = ' + || topogeom.id || ' AND layer_id = ' + || topogeom.layer_id || ' AND element_type = 3 '; + EXECUTE sql INTO geom; + + ELSIF topogeom.type = 2 THEN -- [multi]line -- }{ + + sql := + 'SELECT st_multi(ST_LineMerge(ST_Collect(e.geom))) as g FROM ' + || quote_ident(toponame) || '.edge e, ' + || quote_ident(toponame) || '.relation r ' + || ' WHERE r.topogeo_id = ' || topogeom.id + || ' AND r.layer_id = ' || topogeom.layer_id + || ' AND r.element_type = 2 ' + || ' AND abs(r.element_id) = e.edge_id'; + EXECUTE sql INTO geom; + + ELSIF topogeom.type = 1 THEN -- [multi]point -- }{ + + sql := + 'SELECT st_multi(st_union(n.geom)) as g FROM ' + || quote_ident(toponame) || '.node n, ' + || quote_ident(toponame) || '.relation r ' + || ' WHERE r.topogeo_id = ' || topogeom.id + || ' AND r.layer_id = ' || topogeom.layer_id + || ' AND r.element_type = 1 ' + || ' AND r.element_id = n.node_id'; + EXECUTE sql INTO geom; + + ELSIF topogeom.type = 4 THEN -- mixed collection -- }{ - ELSIF topogeom.type = 4 THEN -- mixed collection sql := 'WITH areas AS ( SELECT ST_Union(' || 'topology.ST_GetFaceGeometry(' || quote_literal(toponame) || ',' @@ -1297,18 +1283,28 @@ BEGIN || ' AND r.element_id = n.node_id ), ' || ' un as ( SELECT g FROM areas UNION ALL SELECT g FROM lines ' || ' UNION ALL SELECT g FROM points ) ' - || 'SELECT ST_Collect(g) FROM un'; + || 'SELECT ST_Multi(ST_Collect(g)) FROM un'; EXECUTE sql INTO geom; - IF geom IS NULL THEN + + ELSE -- }{ + + RAISE EXCEPTION 'Invalid TopoGeometries (unknown type %)', topogeom.type; + + END IF; -- } + + IF geom IS NULL THEN + IF topogeom.type = 3 THEN -- [multi]polygon + geom := 'MULTIPOLYGON EMPTY'; + ELSIF topogeom.type = 2 THEN -- [multi]line + geom := 'MULTILINESTRING EMPTY'; + ELSIF topogeom.type = 1 THEN -- [multi]point + geom := 'MULTIPOINT EMPTY'; + ELSE geom := 'GEOMETRYCOLLECTION EMPTY'; END IF; - - ELSE - RAISE NOTICE 'Geometry from TopoGeometry does not support TopoGeometries of type % so far', topogeom.type; - geom := 'GEOMETRYCOLLECTION EMPTY'; END IF; - RETURN geom; + RETURN geom; END $$ LANGUAGE 'plpgsql' VOLATILE STRICT;