diff --git a/citydb-database-postgres/src/main/java/org/citydb/database/postgres/SchemaAdapter.java b/citydb-database-postgres/src/main/java/org/citydb/database/postgres/SchemaAdapter.java index 14115eb7..23fb0f72 100644 --- a/citydb-database-postgres/src/main/java/org/citydb/database/postgres/SchemaAdapter.java +++ b/citydb-database-postgres/src/main/java/org/citydb/database/postgres/SchemaAdapter.java @@ -91,8 +91,7 @@ public String getFeatureHierarchyQuery() { try { return PlainText.of(featureHierarchyQuery.get(), "F.ENVELOPE", - "G.GEOMETRY", - "A.MULTI_POINT").toString(); + "G.GEOMETRY").toString(); } catch (Exception e) { throw new IllegalStateException("Failed to create feature hierarchy query.", e); } @@ -103,8 +102,7 @@ public String getFeatureHierarchyQuery(int targetSRID) { try { return PlainText.of(featureHierarchyQuery.get(), "st_transform(F.ENVELOPE, " + targetSRID + ")", - "st_transform(G.GEOMETRY, " + targetSRID + ")", - "st_transform(A.MULTI_POINT, " + targetSRID + ")").toString(); + "st_transform(G.GEOMETRY, " + targetSRID + ")").toString(); } catch (Exception e) { throw new IllegalStateException("Failed to create feature hierarchy query.", e); } diff --git a/citydb-database-postgres/src/main/resources/org/citydb/database/postgres/query_feature_hierarchy.sql b/citydb-database-postgres/src/main/resources/org/citydb/database/postgres/query_feature_hierarchy.sql index 7f2e406a..178bfc5a 100644 --- a/citydb-database-postgres/src/main/resources/org/citydb/database/postgres/query_feature_hierarchy.sql +++ b/citydb-database-postgres/src/main/resources/org/citydb/database/postgres/query_feature_hierarchy.sql @@ -57,7 +57,7 @@ WITH RECURSIVE FEATURE_HIERARCHY AS FROM @SCHEMA@.PROPERTY P INNER JOIN FEATURE_HIERARCHY H ON H.VAL_FEATURE_ID = P.FEATURE_ID AND H.VAL_RELATION_TYPE = 1 WHERE NOT IS_CYCLE) -SELECT DISTINCT ON (H.ID) +SELECT H.ID, H.FEATURE_ID, H.PARENT_ID, @@ -97,22 +97,7 @@ SELECT DISTINCT ON (H.ID) F.VALID_TO, {} AS GEOMETRY, G.GEOMETRY_PROPERTIES, - G.FEATURE_ID AS GEOMETRY_FEATURE_ID, - A.OBJECTID AS ADDRESS_OBJECTID, - A.IDENTIFIER AS ADDRESS_IDENTIFIER, - A.IDENTIFIER_CODESPACE AS ADDRESS_IDENTIFIER_CODESPACE, - A.STREET, - A.HOUSE_NUMBER, - A.PO_BOX, - A.ZIP_CODE, - A.CITY, - A.STATE, - A.COUNTRY, - A.FREE_TEXT, - {} AS MULTI_POINT, - A.CONTENT, - A.CONTENT_MIME_TYPE + G.FEATURE_ID AS GEOMETRY_FEATURE_ID FROM FEATURE_HIERARCHY H LEFT JOIN @SCHEMA@.FEATURE F ON F.ID = H.VAL_FEATURE_ID LEFT JOIN @SCHEMA@.GEOMETRY_DATA G ON G.ID = H.VAL_GEOMETRY_ID -LEFT JOIN @SCHEMA@.ADDRESS A ON A.ID = H.VAL_ADDRESS_ID \ No newline at end of file diff --git a/citydb-database/src/main/java/org/citydb/database/util/IndexHelper.java b/citydb-database/src/main/java/org/citydb/database/util/IndexHelper.java index 0fe13089..c475c7d1 100644 --- a/citydb-database/src/main/java/org/citydb/database/util/IndexHelper.java +++ b/citydb-database/src/main/java/org/citydb/database/util/IndexHelper.java @@ -53,7 +53,6 @@ public class IndexHelper { Index.PROPERTY_VAL_TIMESTAMP, Index.PROPERTY_VAL_DOUBLE, Index.PROPERTY_VAL_INT, - Index.PROPERTY_VAL_LOD, Index.PROPERTY_VAL_STRING, Index.PROPERTY_VAL_UOM, Index.PROPERTY_VAL_URI)); diff --git a/citydb-operation/src/main/java/org/citydb/operation/exporter/address/AddressExporter.java b/citydb-operation/src/main/java/org/citydb/operation/exporter/address/AddressExporter.java index 7a8578b1..dc37873f 100644 --- a/citydb-operation/src/main/java/org/citydb/operation/exporter/address/AddressExporter.java +++ b/citydb-operation/src/main/java/org/citydb/operation/exporter/address/AddressExporter.java @@ -33,54 +33,84 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; +import java.util.Set; public class AddressExporter extends DatabaseExporter { + private final Table address; + private final Select select; public AddressExporter(ExportHelper helper) throws SQLException { super(helper); - stmt = helper.getConnection().prepareStatement(getQuery().toSql()); + address = tableHelper.getTable(org.citydb.database.schema.Table.ADDRESS); + select = getBaseQuery(); + stmt = helper.getConnection().prepareStatement(Select.of(select) + .where(address.column("id").eq(Placeholder.empty())) + .toSql()); } - private Select getQuery() { - Table address = tableHelper.getTable(org.citydb.database.schema.Table.ADDRESS); + private Select getBaseQuery() { return Select.newInstance() - .select(address.columns(Map.of("objectid", "address_objectid", "identifier", "address_identifier", - "identifier_codespace", "address_identifier_codespace"))) - .select(address.columns("street", "house_number", "po_box", "zip_code", "city", - "state", "country", "free_text", "content", "content_mime_type")) + .select(address.columns("id", "objectid", "identifier", "identifier_codespace", "street", + "house_number", "po_box", "zip_code", "city", "state", "country", "free_text", "content", + "content_mime_type")) .select(helper.getTransformOperator(address.column("multi_point"))) - .from(address) - .where(address.column("id").eq(Placeholder.empty())); + .from(address); + } + + private Select getQuery(Set ids) { + return Select.of(select) + .where(operationHelper.in(address.column("id"), ids)); } public Address doExport(long id) throws ExportException, SQLException { stmt.setLong(1, id); try (ResultSet rs = stmt.executeQuery()) { - if (rs.next()) { - return doExport(id, rs); - } + return doExport(rs).get(id); } + } - return null; + public Map doExport(Set ids) throws ExportException, SQLException { + if (ids.size() == 1) { + stmt.setLong(1, ids.iterator().next()); + try (ResultSet rs = stmt.executeQuery()) { + return doExport(rs); + } + } else if (!ids.isEmpty()) { + try (Statement stmt = helper.getConnection().createStatement(); + ResultSet rs = stmt.executeQuery(getQuery(ids).toSql())) { + return doExport(rs); + } + } else { + return Collections.emptyMap(); + } } - public Address doExport(long addressId, ResultSet rs) throws ExportException, SQLException { - return Address.newInstance() - .setObjectId(rs.getString("address_objectid")) - .setIdentifier(rs.getString("address_identifier")) - .setIdentifierCodeSpace(rs.getString("address_identifier_codespace")) - .setStreet(rs.getString("street")) - .setHouseNumber(rs.getString("house_number")) - .setPoBox(rs.getString("po_box")) - .setZipCode(rs.getString("zip_code")) - .setCity(rs.getString("city")) - .setState(rs.getString("state")) - .setCountry(rs.getString("country")) - .setFreeText(getArrayValue(rs.getString("free_text"))) - .setMultiPoint(getGeometry(rs.getObject("multi_point"), MultiPoint.class)) - .setGenericContent(rs.getString("content")) - .setGenericContentMimeType(rs.getString("content_mime_type")) - .setDescriptor(AddressDescriptor.of(addressId)); + private Map doExport(ResultSet rs) throws ExportException, SQLException { + Map addresses = new HashMap<>(); + while (rs.next()) { + long id = rs.getLong("id"); + addresses.put(id, Address.newInstance() + .setObjectId(rs.getString("objectid")) + .setIdentifier(rs.getString("identifier")) + .setIdentifierCodeSpace(rs.getString("identifier_codespace")) + .setStreet(rs.getString("street")) + .setHouseNumber(rs.getString("house_number")) + .setPoBox(rs.getString("po_box")) + .setZipCode(rs.getString("zip_code")) + .setCity(rs.getString("city")) + .setState(rs.getString("state")) + .setCountry(rs.getString("country")) + .setFreeText(getArrayValue(rs.getString("free_text"))) + .setMultiPoint(getGeometry(rs.getObject("multi_point"), MultiPoint.class)) + .setGenericContent(rs.getString("content")) + .setGenericContentMimeType(rs.getString("content_mime_type")) + .setDescriptor(AddressDescriptor.of(id))); + } + + return addresses; } } diff --git a/citydb-operation/src/main/java/org/citydb/operation/exporter/geometry/ImplicitGeometryExporter.java b/citydb-operation/src/main/java/org/citydb/operation/exporter/geometry/ImplicitGeometryExporter.java index 65af6f56..15d63f6e 100644 --- a/citydb-operation/src/main/java/org/citydb/operation/exporter/geometry/ImplicitGeometryExporter.java +++ b/citydb-operation/src/main/java/org/citydb/operation/exporter/geometry/ImplicitGeometryExporter.java @@ -95,7 +95,12 @@ public ImplicitGeometry doExport(long id) throws ExportException, SQLException { } public Map doExport(Set ids, Collection appearances) throws ExportException, SQLException { - if (!ids.isEmpty()) { + if (ids.size() == 1) { + stmt.setLong(1, ids.iterator().next()); + try (ResultSet rs = stmt.executeQuery()) { + return doExport(appearances, rs); + } + } else if (!ids.isEmpty()) { try (Statement stmt = helper.getConnection().createStatement(); ResultSet rs = stmt.executeQuery(getQuery(ids).toSql())) { return doExport(appearances, rs); diff --git a/citydb-operation/src/main/java/org/citydb/operation/exporter/hierarchy/HierarchyBuilder.java b/citydb-operation/src/main/java/org/citydb/operation/exporter/hierarchy/HierarchyBuilder.java index fe38f94d..bcc8b270 100644 --- a/citydb-operation/src/main/java/org/citydb/operation/exporter/hierarchy/HierarchyBuilder.java +++ b/citydb-operation/src/main/java/org/citydb/operation/exporter/hierarchy/HierarchyBuilder.java @@ -69,6 +69,7 @@ public static HierarchyBuilder newInstance(long rootId, ExportHelper helper) { public HierarchyBuilder initialize(ResultSet rs) throws ExportException, SQLException { Set appearanceIds = new HashSet<>(); + Set addressIds = new HashSet<>(); Set implicitGeometryIds = new HashSet<>(); while (rs.next()) { @@ -94,9 +95,8 @@ public HierarchyBuilder initialize(ResultSet rs) throws ExportException, SQLExce } long addressId = rs.getLong("val_address_id"); - if (!rs.wasNull() && hierarchy.getAddress(addressId) == null) { - hierarchy.addAddress(addressId, tableHelper.getOrCreateExporter(AddressExporter.class) - .doExport(addressId, rs)); + if (!rs.wasNull()) { + addressIds.add(addressId); } long implicitGeometryId = rs.getLong("val_implicitgeom_id"); @@ -114,15 +114,23 @@ public HierarchyBuilder initialize(ResultSet rs) throws ExportException, SQLExce } } - if (exportAppearances) { + if (exportAppearances && !appearanceIds.isEmpty()) { tableHelper.getOrCreateExporter(AppearanceExporter.class) .doExport(appearanceIds, implicitGeometryIds) .forEach(hierarchy::addAppearance); } - tableHelper.getOrCreateExporter(ImplicitGeometryExporter.class) - .doExport(implicitGeometryIds, hierarchy.getAppearances().values()) - .forEach(hierarchy::addImplicitGeometry); + if (!addressIds.isEmpty()) { + tableHelper.getOrCreateExporter(AddressExporter.class) + .doExport(addressIds) + .forEach(hierarchy::addAddress); + } + + if (!implicitGeometryIds.isEmpty()) { + tableHelper.getOrCreateExporter(ImplicitGeometryExporter.class) + .doExport(implicitGeometryIds, hierarchy.getAppearances().values()) + .forEach(hierarchy::addImplicitGeometry); + } return this; } diff --git a/resources/3dcitydb/postgresql/sql-scripts/citydb-pkg/delete.sql b/resources/3dcitydb/postgresql/sql-scripts/citydb-pkg/delete.sql index 774dec7b..9b613e2d 100644 --- a/resources/3dcitydb/postgresql/sql-scripts/citydb-pkg/delete.sql +++ b/resources/3dcitydb/postgresql/sql-scripts/citydb-pkg/delete.sql @@ -201,7 +201,7 @@ BEGIN (SELECT DISTINCT unnest(feature_ids) AS a_id) a LEFT JOIN property p - ON p.val_feature_id = a.a_id + ON p.val_feature_id = a.a_id WHERE p.val_feature_id IS NULL OR p.val_relation_type IS NULL OR p.val_relation_type = 0; END IF; @@ -216,7 +216,11 @@ BEGIN PERFORM citydb_pkg.delete_implicit_geometry(array_agg(a.a_id)) FROM - (SELECT DISTINCT unnest(implicit_geometry_ids) AS a_id) a; + (SELECT DISTINCT unnest(implicit_geometry_ids) AS a_id) a + LEFT JOIN + property p + ON p.val_implicitgeom_id = a.a_id + WHERE p.val_implicitgeom_id IS NULL; END IF; IF -1 = ALL(appearance_ids) IS NOT NULL THEN diff --git a/resources/3dcitydb/postgresql/sql-scripts/schema/schema.sql b/resources/3dcitydb/postgresql/sql-scripts/schema/schema.sql index d731c1d4..906f439b 100644 --- a/resources/3dcitydb/postgresql/sql-scripts/schema/schema.sql +++ b/resources/3dcitydb/postgresql/sql-scripts/schema/schema.sql @@ -233,31 +233,31 @@ CREATE INDEX property_namespace_inx ON property ( namespace_id ); CREATE INDEX property_name_inx ON property ( name ); -CREATE INDEX property_val_feature_fkx ON property ( val_feature_id ) WHERE val_feature_id IS NOT NULL; - CREATE INDEX property_val_string_inx ON property ( val_string ) WHERE val_string IS NOT NULL; CREATE INDEX property_val_uom_inx ON property ( val_uom ) WHERE val_uom IS NOT NULL; CREATE INDEX property_val_uri_inx ON property ( val_uri ) WHERE val_uri IS NOT NULL; -CREATE INDEX property_val_lod_inx ON property ( val_lod ) WHERE val_lod IS NOT NULL; - CREATE INDEX property_val_int_inx ON property ( val_int ) WHERE val_int IS NOT NULL; CREATE INDEX property_val_double_inx ON property ( val_double ) WHERE val_double IS NOT NULL; CREATE INDEX property_val_date_inx ON property ( val_timestamp ) WHERE val_timestamp IS NOT NULL; -CREATE INDEX property_val_geometry_fkx ON property ( val_geometry_id ) WHERE val_geometry_id IS NOT NULL; +CREATE INDEX property_val_feature_fkx ON property ( val_feature_id ); + +CREATE INDEX property_val_geometry_fkx ON property ( val_geometry_id ); + +CREATE INDEX property_val_implicitgeom_fkx ON property ( val_implicitgeom_id ); -CREATE INDEX property_val_implicitgeom_fkx ON property ( val_implicitgeom_id ) WHERE val_implicitgeom_id IS NOT NULL; +CREATE INDEX property_val_appearance_fkx ON property ( val_appearance_id ); -CREATE INDEX property_val_appearance_fkx ON property ( val_appearance_id ) WHERE val_appearance_id IS NOT NULL; +CREATE INDEX property_val_relation_type_inx ON property ( val_relation_type ); -CREATE INDEX property_val_relation_type_inx ON property ( val_relation_type ) WHERE val_relation_type IS NOT NULL; +CREATE INDEX property_val_address_fkx ON property ( val_address_id ); -CREATE INDEX property_val_address_fkx ON property ( val_address_id ) WHERE val_address_id IS NOT NULL; +CREATE INDEX property_val_lod_inx ON property ( val_lod ); CREATE TABLE surface_data ( id bigint DEFAULT nextval('surface_data_seq'::regclass) NOT NULL ,