From: Sandro Santilli Date: Wed, 9 Mar 2011 19:18:45 +0000 (+0000) Subject: Ticket #856: topology.CopyTopology(text,text) implementation, test and documentation X-Git-Tag: 2.0.0alpha1~1913 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e5ca72613d0f63126e36eeea82b0a74a11040647;p=postgis Ticket #856: topology.CopyTopology(text,text) implementation, test and documentation git-svn-id: http://svn.osgeo.org/postgis/trunk@6888 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/doc/extras_topology.xml b/doc/extras_topology.xml index ac39a866a..eeaecf27d 100644 --- a/doc/extras_topology.xml +++ b/doc/extras_topology.xml @@ -393,6 +393,54 @@ topoid + + + CopyTopology + Makes a copy of a topology structure (nodes, edges, faces, layers and TopoGeometries). + + + + + + integer CopyTopology + varchar existing_topology_name + varchar new_name + + + + + + Description + + +Creates a new topology with name new_topology_name and SRID and precision taken from existing_topology_name, copies all nodes, edges and faces in there, copies layers and their TopoGeometries too. + + + +The new rows in topology.layer will contain synthetized values for schema_name, table_name and feature_column. This is because the TopoGeometry will only exist as a definition but won't be available in any user-level table yet. + + + + Availability: 2.0.0 + + + + + Examples + +This example makes a backup of a topology called ma_topo + + SELECT topology.CopyTopology('ma_topo', 'ma_topo_bakup'); + + + + + + See Also + + , + + DropTopoGeometryColumn diff --git a/topology/Makefile.in b/topology/Makefile.in index a0ec01b47..9e19bc322 100644 --- a/topology/Makefile.in +++ b/topology/Makefile.in @@ -42,7 +42,7 @@ endif $(SQL_OBJS): %.in: %.in.c $(CPP) -traditional-cpp $< | grep -v '^#' > $@ -topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/gml.sql sql/query/getnodebypoint.sql sql/query/getedgebypoint.sql sql/manage/TopologySummary.sql +topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/gml.sql sql/query/getnodebypoint.sql sql/query/getedgebypoint.sql sql/manage/TopologySummary.sql sql/manage/CopyTopology.sql check: topology.sql $(MAKE) -C test $@ diff --git a/topology/sql/manage/CopyTopology.sql b/topology/sql/manage/CopyTopology.sql new file mode 100644 index 000000000..a44ec675a --- /dev/null +++ b/topology/sql/manage/CopyTopology.sql @@ -0,0 +1,100 @@ +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- PostGIS - Spatial Types for PostgreSQL +-- http://postgis.refractions.net +-- +-- Copyright (C) 2011 Sandro Santilli +-- +-- This is free software; you can redistribute and/or modify it under +-- the terms of the GNU General Public Licence. See the COPYING file. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +--{ +-- CopyTopology(name_source, name_target) +-- +-- Makes a copy of a topology (primitives + topogeometry collections) . +-- Returns the new topology id. +-- +CREATE OR REPLACE FUNCTION topology.CopyTopology(atopology varchar, + newtopo varchar) +RETURNS int +AS +$$ +DECLARE + rec RECORD; + rec2 RECORD; + oldtopo_id integer; + newtopo_id integer; + n int4; + ret text; +BEGIN + + SELECT * FROM topology.topology where name = atopology + INTO strict rec; + oldtopo_id = rec.id; + -- TODO: more gracefully handle unexistent topology + + SELECT topology.CreateTopology(newtopo, rec.SRID, rec.precision) + INTO strict newtopo_id; + + -- Copy faces + EXECUTE 'INSERT INTO ' || quote_ident(newtopo) + || '.face SELECT * FROM ' || quote_ident(atopology) + || '.face WHERE face_id != 0'; + -- Update faces sequence + EXECUTE 'SELECT setval(' || quote_literal( + quote_ident(newtopo) || '.face_face_id_seq' + ) || ', (SELECT last_value FROM ' + || quote_ident(atopology) || '.face_face_id_seq))'; + + -- Copy nodes + EXECUTE 'INSERT INTO ' || quote_ident(newtopo) + || '.node SELECT * FROM ' || quote_ident(atopology) + || '.node'; + -- Update node sequence + EXECUTE 'SELECT setval(' || quote_literal( + quote_ident(newtopo) || '.node_node_id_seq' + ) || ', (SELECT last_value FROM ' + || quote_ident(atopology) || '.node_node_id_seq))'; + + -- Copy edges + EXECUTE 'INSERT INTO ' || quote_ident(newtopo) + || '.edge_data SELECT * FROM ' || quote_ident(atopology) + || '.edge_data'; + -- Update edge sequence + EXECUTE 'SELECT setval(' || quote_literal( + quote_ident(newtopo) || '.edge_data_edge_id_seq' + ) || ', (SELECT last_value FROM ' + || quote_ident(atopology) || '.edge_data_edge_id_seq))'; + + -- Copy layers and their TopoGeometry sequences + FOR rec IN SELECT * FROM topology.layer WHERE topology_id = oldtopo_id + LOOP + INSERT INTO topology.layer (topology_id, layer_id, feature_type, + level, child_id, schema_name, table_name, feature_column) + VALUES (newtopo_id, rec.layer_id, rec.feature_type, + rec.level, rec.child_id, newtopo, + 'LAYER' || rec.layer_id, ''); + -- Create layer's TopoGeometry sequences + EXECUTE 'SELECT last_value FROM ' + || quote_ident(atopology) || '.topogeo_s_' || rec.layer_id + INTO STRICT n; + EXECUTE 'CREATE SEQUENCE ' || quote_ident(newtopo) + || '.topogeo_s_' || rec.layer_id; + EXECUTE 'SELECT setval(' || quote_literal( + quote_ident(newtopo) || '.topogeo_s_' || rec.layer_id + ) || ', ' || n || ')'; + END LOOP; + + -- Copy TopoGeometry definitions + EXECUTE 'INSERT INTO ' || quote_ident(newtopo) + || '.relation SELECT * FROM ' || quote_ident(atopology) + || '.relation'; + + RETURN newtopo_id; +END +$$ +LANGUAGE 'plpgsql' VOLATILE STRICT; + +--} TopologySummary diff --git a/topology/test/Makefile b/topology/test/Makefile index 7980de407..ee384eee1 100644 --- a/topology/test/Makefile +++ b/topology/test/Makefile @@ -30,6 +30,7 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \ regress/topoelement.sql \ regress/topoelementarray_agg.sql \ regress/droptopology.sql \ + regress/copytopology.sql \ regress/createtopogeom.sql \ regress/gml.sql \ regress/getnodebypoint.sql \ diff --git a/topology/test/regress/copytopology.sql b/topology/test/regress/copytopology.sql new file mode 100644 index 000000000..a914bac78 --- /dev/null +++ b/topology/test/regress/copytopology.sql @@ -0,0 +1,53 @@ +set client_min_messages to WARNING; + +INSERT INTO spatial_ref_sys ( auth_name, auth_srid, srid, proj4text ) VALUES ( 'EPSG', 4326, 4326, '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' ); +\i load_topology-4326.sql +\i load_features.sql +\i more_features.sql + +SELECT topology.CopyTopology('city_data', 'CITY_data_UP_down') > 0; + +SELECT srid,precision FROM topology.topology WHERE name = 'CITY_data_UP_down'; + +SELECT 'nodes', count(node_id) FROM "CITY_data_UP_down".node; +SELECT * FROM "CITY_data_UP_down".node EXCEPT +SELECT * FROM "city_data".node; + +SELECT 'edges', count(edge_id) FROM "CITY_data_UP_down".edge_data; +SELECT * FROM "CITY_data_UP_down".edge EXCEPT +SELECT * FROM "city_data".edge; + +SELECT 'faces', count(face_id) FROM "CITY_data_UP_down".face; +SELECT * FROM "CITY_data_UP_down".face EXCEPT +SELECT * FROM "city_data".face; + +SELECT 'relations', count(*) FROM "CITY_data_UP_down".relation; +SELECT * FROM "CITY_data_UP_down".relation EXCEPT +SELECT * FROM "city_data".relation; + +SELECT 'layers', count(l.*) FROM topology.layer l, topology.topology t +WHERE l.topology_id = t.id and t.name = 'CITY_data_UP_down'; +SELECT l.layer_id, l.feature_type, l.level FROM topology.layer l, +topology.topology t where l.topology_id = t.id and t.name = 'CITY_data_UP_down' +EXCEPT +SELECT l.layer_id, l.feature_type, l.level FROM topology.layer l, +topology.topology t where l.topology_id = t.id and t.name = 'city_data'; + +SELECT l.layer_id, l.schema_name, l.table_name, l.feature_column +FROM topology.layer l, topology.topology t +WHERE l.topology_id = t.id and t.name = 'CITY_data_UP_down' +ORDER BY l.layer_id; + +-- Check sequences +SELECT * from "CITY_data_UP_down".node_node_id_seq; +SELECT * from "CITY_data_UP_down".edge_data_edge_id_seq; +SELECT * from "CITY_data_UP_down".face_face_id_seq; +SELECT * from "CITY_data_UP_down".layer_id_seq; +SELECT * from "CITY_data_UP_down".topogeo_s_1; +SELECT * from "CITY_data_UP_down".topogeo_s_2; +SELECT * from "CITY_data_UP_down".topogeo_s_3; + +SELECT topology.DropTopology('CITY_data_UP_down'); +SELECT topology.DropTopology('city_data'); +DROP SCHEMA features CASCADE; +DELETE FROM spatial_ref_sys where srid = 4326; diff --git a/topology/test/regress/copytopology_expected b/topology/test/regress/copytopology_expected new file mode 100644 index 000000000..afeccd7ca --- /dev/null +++ b/topology/test/regress/copytopology_expected @@ -0,0 +1,30 @@ +BEGIN +t +8 +22 +26 +COMMIT +BEGIN +1 +2 +3 +COMMIT +t +4326|0 +nodes|22 +edges|24 +faces|10 +relations|39 +layers|3 +1|CITY_data_UP_down|LAYER1| +2|CITY_data_UP_down|LAYER2| +3|CITY_data_UP_down|LAYER3| +node_node_id_seq|22|1|1|9223372036854775807|1|1|0|f|t +edge_data_edge_id_seq|26|1|1|9223372036854775807|1|1|0|f|t +face_face_id_seq|8|1|1|9223372036854775807|1|1|0|f|t +layer_id_seq|1|1|1|9223372036854775807|1|1|1|f|f +topogeo_s_1|9|1|1|9223372036854775807|1|1|0|f|t +topogeo_s_2|8|1|1|9223372036854775807|1|1|0|f|t +topogeo_s_3|8|1|1|9223372036854775807|1|1|0|f|t +Topology 'CITY_data_UP_down' dropped +Topology 'city_data' dropped diff --git a/topology/topology.sql.in.c b/topology/topology.sql.in.c index 518e346a9..01c3a2f01 100644 --- a/topology/topology.sql.in.c +++ b/topology/topology.sql.in.c @@ -1908,6 +1908,7 @@ LANGUAGE 'plpgsql' VOLATILE STRICT; --} DropTopology #include "sql/manage/TopologySummary.sql" +#include "sql/manage/CopyTopology.sql" --={ ---------------------------------------------------------------- -- POSTGIS-SPECIFIC topology predicates